From 8a3437d84f4c43534d6ef3b3cafa0b48d4afdb31 Mon Sep 17 00:00:00 2001 From: Matt Rice Date: Fri, 7 Jul 2023 17:32:34 -0400 Subject: [PATCH 1/2] chore: relicense Signed-off-by: Matt Rice --- LICENSE | 702 ++---------------- README.md | 7 + contracts/AcrossConfigStore.sol | 2 +- contracts/Arbitrum_SpokePool.sol | 2 +- contracts/Boba_SpokePool.sol | 2 +- contracts/BondToken.sol | 2 +- contracts/Ethereum_SpokePool.sol | 2 +- contracts/HubPool.sol | 2 +- contracts/Lockable.sol | 2 +- contracts/LpTokenFactory.sol | 2 +- contracts/MerkleLib.sol | 2 +- contracts/Optimism_SpokePool.sol | 2 +- contracts/Ovm_SpokePool.sol | 2 +- contracts/PolygonTokenBridger.sol | 2 +- contracts/Polygon_SpokePool.sol | 2 +- contracts/SpokePool.sol | 2 +- contracts/Succinct_SpokePool.sol | 2 +- contracts/ZkSync_SpokePool.sol | 2 +- contracts/chain-adapters/Arbitrum_Adapter.sol | 2 +- .../chain-adapters/Arbitrum_RescueAdapter.sol | 2 +- .../Arbitrum_SendTokensAdapter.sol | 2 +- contracts/chain-adapters/Boba_Adapter.sol | 2 +- contracts/chain-adapters/Ethereum_Adapter.sol | 2 +- .../chain-adapters/Ethereum_RescueAdapter.sol | 2 +- contracts/chain-adapters/Mock_Adapter.sol | 2 +- contracts/chain-adapters/Optimism_Adapter.sol | 2 +- contracts/chain-adapters/Polygon_Adapter.sol | 2 +- contracts/chain-adapters/Succinct_Adapter.sol | 2 +- contracts/chain-adapters/ZkSync_Adapter.sol | 2 +- .../interfaces/AdapterInterface.sol | 2 +- contracts/erc1155/MintableERC1155.sol | 2 +- .../external/interfaces/WETH9Interface.sol | 2 +- contracts/interfaces/HubPoolInterface.sol | 2 +- .../interfaces/LpTokenFactoryInterface.sol | 2 +- contracts/interfaces/SpokePoolInterface.sol | 2 +- .../AcrossMerkleDistributor.sol | 2 +- contracts/test/AcrossMessageHandlerMock.sol | 2 +- contracts/test/ArbitrumMocks.sol | 2 +- contracts/test/MerkleLibTest.sol | 2 +- contracts/test/MockBedrockStandardBridge.sol | 2 +- contracts/test/MockOptimism_SpokePool.sol | 2 +- contracts/test/PolygonERC20Test.sol | 2 +- contracts/test/PolygonMocks.sol | 2 +- contracts/test/SuccinctMocks.sol | 2 +- .../EIP712CrossChainUpgradeable.sol | 2 +- .../upgradeable/MultiCallerUpgradeable.sol | 2 +- .../arbitrum-goerli/Arbitrum_SpokePool.json | 2 +- .../2703c51b0457010edb5371429c04306b.json | 80 +- .../arbitrum-rinkeby/Arbitrum_SpokePool.json | 2 +- .../c8b9349311d8b5049b613ac98eb998d0.json | 70 +- deployments/arbitrum/Arbitrum_SpokePool.json | 2 +- .../1a5892b796c4f5bdf21d8cd0d15027f4.json | 78 +- deployments/boba/Boba_SpokePool.json | 2 +- .../4d00864cb95f68f23bc763892eeb3451.json | 78 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 +- deployments/goerli/AcrossConfigStore.json | 2 +- .../goerli/AcrossMerkleDistributor.json | 2 +- deployments/goerli/Arbitrum_Adapter.json | 2 +- deployments/goerli/Ethereum_Adapter.json | 2 +- deployments/goerli/Ethereum_SpokePool.json | 2 +- deployments/goerli/LpTokenFactory.json | 2 +- deployments/goerli/ZkSync_Adapter.json | 2 +- .../0c0f7cf4c33344752a752d4aad8f0613.json | 94 +-- .../4972f5cae7c6e9deea3ed342ae0a0eeb.json | 88 +-- .../b9d6747074e2e4e0305d51ac3373cf9e.json | 94 +-- .../e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json | 108 +-- .../f5a0c3a42678b8be065d2d7cfda0e784.json | 90 +-- deployments/kovan/AcrossConfigStore.json | 2 +- deployments/kovan/Ethereum_Adapter.json | 2 +- deployments/kovan/Ethereum_SpokePool.json | 2 +- deployments/kovan/LpTokenFactory.json | 2 +- deployments/kovan/Optimism_Adapter.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 +- .../f654478e897007c7ba14581b070ec005.json | 38 +- deployments/mainnet/AcrossConfigStore.json | 2 +- deployments/mainnet/Arbitrum_Adapter.json | 2 +- .../mainnet/Arbitrum_RescueAdapter.json | 2 +- .../mainnet/Arbitrum_SendTokensAdapter.json | 2 +- deployments/mainnet/Boba_Adapter.json | 2 +- deployments/mainnet/Ethereum_Adapter.json | 2 +- deployments/mainnet/Ethereum_SpokePool.json | 2 +- deployments/mainnet/LpTokenFactory.json | 2 +- deployments/mainnet/Optimism_Adapter.json | 2 +- deployments/mainnet/PolygonTokenBridger.json | 2 +- deployments/mainnet/Polygon_Adapter.json | 2 +- .../2433465a1be70a13b6719df6fea2831a.json | 72 +- .../375f3de1549a735f4b746d114c8a6633.json | 38 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 +- .../778ed9956c3f76e793496228f16e1373.json | 22 +- .../80d9895099d6448454133a653020a62d.json | 74 +- .../9ecc79ca0809d14763bad8554b06546b.json | 94 +-- .../a254ea7a050d78a978809e4c33fcb9ff.json | 6 +- .../aa94850b4a0bee17111a41299cfa0033.json | 94 +-- .../ac469a0c874627ad85d8b93b55e7f3fc.json | 76 +- .../b20d5afcf396996ae08652b8281973a7.json | 72 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 +- .../f654478e897007c7ba14581b070ec005.json | 38 +- .../optimism-kovan/Optimism_SpokePool.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 +- deployments/optimism/Optimism_SpokePool.json | 2 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 +- .../polygon-mumbai/MintableERC1155.json | 2 +- .../polygon-mumbai/PolygonTokenBridger.json | 2 +- .../polygon-mumbai/Polygon_SpokePool.json | 2 +- .../200193942e0f09d7ebb5ccce1bc305e7.json | 2 +- .../2a98e0c4f048f0fda1d4cc9162127646.json | 2 +- .../c0d608dcade73b41bfb146ca48293092.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 +- deployments/polygon/MintableERC1155.json | 2 +- deployments/polygon/PolygonTokenBridger.json | 2 +- deployments/polygon/Polygon_SpokePool.json | 2 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 +- .../b20d5afcf396996ae08652b8281973a7.json | 72 +- .../ea9229ed188f1300c4a413d030dbf1b6.json | 2 +- deployments/rinkeby/Arbitrum_Adapter.json | 2 +- deployments/rinkeby/Ethereum_Adapter.json | 2 +- deployments/rinkeby/Ethereum_SpokePool.json | 2 +- deployments/rinkeby/LpTokenFactory.json | 2 +- deployments/rinkeby/Optimism_Adapter.json | 2 +- deployments/rinkeby/PolygonTokenBridger.json | 2 +- deployments/rinkeby/Polygon_Adapter.json | 2 +- deployments/rinkeby/RateModelStore.json | 2 +- .../1bf8793c065ccb196e5a60f53c731ca8.json | 74 +- .../2fe6c4b637a440a1380be3adbf7d9e12.json | 40 +- .../fc82eeb0fff4196cd4e0dfec8a3b3aca.json | 70 +- .../ee6ad487568ec11f1abbf35d827b46d3.json | 88 +-- 126 files changed, 1350 insertions(+), 1905 deletions(-) diff --git a/LICENSE b/LICENSE index 0ad25db4..c1f149e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,661 +1,99 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 +Business Source License 1.1 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. - Preamble +----------------------------------------------------------------------------- - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. +Parameters - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. +Licensor: Risk Labs - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. +Licensed Work: Across V2 Contracts and Design + The Licensed Work is (c) 2023 Risk Labs - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. +Additional Use Grant: None. - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. +Change Date: The earlier of 2027-07-27 or earlier if Risk Labs + modifies this license. - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. +Change License: GNU General Public License v3.0 or later - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. +----------------------------------------------------------------------------- - The precise terms and conditions for copying, distribution and -modification follow. +Terms - TERMS AND CONDITIONS +The Licensor hereby grants you the right to copy, modify, create derivative +works, redistribute, and make non-production use of the Licensed Work. The +Licensor may make an Additional Use Grant, above, permitting limited +production use. - 0. Definitions. +Effective on the Change Date, or the fourth anniversary of the first publicly +available distribution of a specific version of the Licensed Work under this +License, whichever comes first, the Licensor hereby grants you rights under +the terms of the Change License, and the rights granted in the paragraph +above terminate. - "This License" refers to version 3 of the GNU Affero General Public License. +If your use of the Licensed Work does not comply with the requirements +currently in effect as described in this License, you must purchase a +commercial license from the Licensor, its affiliated entities, or authorized +resellers, or you must refrain from using the Licensed Work. - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. +All copies of the original and modified Licensed Work, and derivative works +of the Licensed Work, are subject to this License. This License applies +separately for each version of the Licensed Work and the Change Date may vary +for each version of the Licensed Work released by Licensor. - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. +You must conspicuously display this License on each original or modified copy +of the Licensed Work. If you receive the Licensed Work in original or +modified form from a third party, the terms and conditions set forth in this +License apply to your use of that work. - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. +Any use of the Licensed Work in violation of this License will automatically +terminate your rights under this License for the current and all other +versions of the Licensed Work. - A "covered work" means either the unmodified Program or a work based -on the Program. +This License does not grant you any right in any trademark or logo of +Licensor or its affiliates (provided that you may use a trademark or logo of +Licensor as expressly required by this License). - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +TITLE. - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. +MariaDB hereby grants you permission to use this License’s text to license +your works, and to refer to it using the trademark "Business Source License", +as long as you comply with the Covenants of Licensor below. - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. +----------------------------------------------------------------------------- - 1. Source Code. +Covenants of Licensor - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. +In consideration of the right to use this License’s text and the "Business +Source License" name and trademark, Licensor covenants to MariaDB, and to all +other recipients of the licensed work to be provided by Licensor: - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. +1. To specify as the Change License the GPL Version 2.0 or any later version, + or a license that is compatible with GPL Version 2.0 or a later version, + where "compatible" means that software provided under the Change License can + be included in a program with software provided under GPL Version 2.0 or a + later version. Licensor may specify additional Change Licenses without + limitation. - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. +2. To either: (a) specify an additional grant of rights to use that does not + impose any additional restriction on the right granted in this License, as + the Additional Use Grant; or (b) insert the text "None". - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. +3. To specify a Change Date. - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. +4. Not to modify this License in any other way. - The Corresponding Source for a work in source code form is that -same work. +----------------------------------------------------------------------------- - 2. Basic Permissions. +Notice - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. +The Business Source License (this document, or the "License") is not an Open +Source license. However, the Licensed Work will eventually be made available +under an Open Source License, as stated in this License. \ No newline at end of file diff --git a/README.md b/README.md index c5193ba2..0c16329f 100644 --- a/README.md +++ b/README.md @@ -69,3 +69,10 @@ These are special instructions for compiling and deploying contracts on `zksync` This step requires [Docker Desktop](https://www.docker.com/products/docker-desktop/) to be running, as the `solc` docker image is fetched as a prerequisite. `yarn compile-zksync` + +## License + +All code in this repository is licensed under BUSL-1.1 unless specified differently in the file. +Individual exceptions to this license can be made by Risk Labs, which holds the rights to this +software and design. If you are interested in using the code or designs in a derivative work, +feel free to reach out to licensing@risklabs.foundation. diff --git a/contracts/AcrossConfigStore.sol b/contracts/AcrossConfigStore.sol index 54eb1a10..00e71ca6 100644 --- a/contracts/AcrossConfigStore.sol +++ b/contracts/AcrossConfigStore.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@uma/core/contracts/common/implementation/MultiCaller.sol"; diff --git a/contracts/Arbitrum_SpokePool.sol b/contracts/Arbitrum_SpokePool.sol index 585f5f05..4fbbea84 100644 --- a/contracts/Arbitrum_SpokePool.sol +++ b/contracts/Arbitrum_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/Boba_SpokePool.sol b/contracts/Boba_SpokePool.sol index 865f8189..d8406303 100644 --- a/contracts/Boba_SpokePool.sol +++ b/contracts/Boba_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Ovm_SpokePool.sol"; diff --git a/contracts/BondToken.sol b/contracts/BondToken.sol index a9afb687..019c24a7 100644 --- a/contracts/BondToken.sol +++ b/contracts/BondToken.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/contracts/Ethereum_SpokePool.sol b/contracts/Ethereum_SpokePool.sol index d6c49178..af77db94 100644 --- a/contracts/Ethereum_SpokePool.sol +++ b/contracts/Ethereum_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/HubPool.sol b/contracts/HubPool.sol index 0a1fc378..33fa6d85 100644 --- a/contracts/HubPool.sol +++ b/contracts/HubPool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./MerkleLib.sol"; diff --git a/contracts/Lockable.sol b/contracts/Lockable.sol index bb86571f..75cbd70f 100644 --- a/contracts/Lockable.sol +++ b/contracts/Lockable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/contracts/LpTokenFactory.sol b/contracts/LpTokenFactory.sol index f947805b..4e06978e 100644 --- a/contracts/LpTokenFactory.sol +++ b/contracts/LpTokenFactory.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/LpTokenFactoryInterface.sol"; diff --git a/contracts/MerkleLib.sol b/contracts/MerkleLib.sol index 4cabce9e..e5310edb 100644 --- a/contracts/MerkleLib.sol +++ b/contracts/MerkleLib.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/SpokePoolInterface.sol"; diff --git a/contracts/Optimism_SpokePool.sol b/contracts/Optimism_SpokePool.sol index fd70342a..fce8a86b 100644 --- a/contracts/Optimism_SpokePool.sol +++ b/contracts/Optimism_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol"; diff --git a/contracts/Ovm_SpokePool.sol b/contracts/Ovm_SpokePool.sol index a7f8ba1b..6e6c60e7 100644 --- a/contracts/Ovm_SpokePool.sol +++ b/contracts/Ovm_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/PolygonTokenBridger.sol b/contracts/PolygonTokenBridger.sol index 7342f2d6..4190031f 100644 --- a/contracts/PolygonTokenBridger.sol +++ b/contracts/PolygonTokenBridger.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Lockable.sol"; diff --git a/contracts/Polygon_SpokePool.sol b/contracts/Polygon_SpokePool.sol index d1d3c1e4..5e0f099b 100644 --- a/contracts/Polygon_SpokePool.sol +++ b/contracts/Polygon_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/SpokePool.sol b/contracts/SpokePool.sol index 0e1ffcbf..58e9f8d9 100644 --- a/contracts/SpokePool.sol +++ b/contracts/SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./MerkleLib.sol"; diff --git a/contracts/Succinct_SpokePool.sol b/contracts/Succinct_SpokePool.sol index 9cb85f3e..b4c7de7c 100644 --- a/contracts/Succinct_SpokePool.sol +++ b/contracts/Succinct_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/ZkSync_SpokePool.sol b/contracts/ZkSync_SpokePool.sol index 6b61c39a..2f5a5f63 100644 --- a/contracts/ZkSync_SpokePool.sol +++ b/contracts/ZkSync_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./SpokePool.sol"; diff --git a/contracts/chain-adapters/Arbitrum_Adapter.sol b/contracts/chain-adapters/Arbitrum_Adapter.sol index b929fc9f..f220c4f9 100644 --- a/contracts/chain-adapters/Arbitrum_Adapter.sol +++ b/contracts/chain-adapters/Arbitrum_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Arbitrum_RescueAdapter.sol b/contracts/chain-adapters/Arbitrum_RescueAdapter.sol index 9c031204..1a66e513 100644 --- a/contracts/chain-adapters/Arbitrum_RescueAdapter.sol +++ b/contracts/chain-adapters/Arbitrum_RescueAdapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol b/contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol index 7ba77c72..944dd5ba 100644 --- a/contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol +++ b/contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Boba_Adapter.sol b/contracts/chain-adapters/Boba_Adapter.sol index 39a259d5..0b2a7384 100644 --- a/contracts/chain-adapters/Boba_Adapter.sol +++ b/contracts/chain-adapters/Boba_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Ethereum_Adapter.sol b/contracts/chain-adapters/Ethereum_Adapter.sol index 84cdf051..c97b9dd3 100644 --- a/contracts/chain-adapters/Ethereum_Adapter.sol +++ b/contracts/chain-adapters/Ethereum_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Ethereum_RescueAdapter.sol b/contracts/chain-adapters/Ethereum_RescueAdapter.sol index d83a5f05..c8fc200a 100644 --- a/contracts/chain-adapters/Ethereum_RescueAdapter.sol +++ b/contracts/chain-adapters/Ethereum_RescueAdapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Mock_Adapter.sol b/contracts/chain-adapters/Mock_Adapter.sol index 840ef1f7..3095ab13 100644 --- a/contracts/chain-adapters/Mock_Adapter.sol +++ b/contracts/chain-adapters/Mock_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Optimism_Adapter.sol b/contracts/chain-adapters/Optimism_Adapter.sol index 7838e75f..ff92d3d3 100644 --- a/contracts/chain-adapters/Optimism_Adapter.sol +++ b/contracts/chain-adapters/Optimism_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Polygon_Adapter.sol b/contracts/chain-adapters/Polygon_Adapter.sol index 1af861bc..53975a12 100644 --- a/contracts/chain-adapters/Polygon_Adapter.sol +++ b/contracts/chain-adapters/Polygon_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/Succinct_Adapter.sol b/contracts/chain-adapters/Succinct_Adapter.sol index 197762a0..511a1f24 100644 --- a/contracts/chain-adapters/Succinct_Adapter.sol +++ b/contracts/chain-adapters/Succinct_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/ZkSync_Adapter.sol b/contracts/chain-adapters/ZkSync_Adapter.sol index d30e8099..d037fc83 100644 --- a/contracts/chain-adapters/ZkSync_Adapter.sol +++ b/contracts/chain-adapters/ZkSync_Adapter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./interfaces/AdapterInterface.sol"; diff --git a/contracts/chain-adapters/interfaces/AdapterInterface.sol b/contracts/chain-adapters/interfaces/AdapterInterface.sol index 95dbbfab..f8143e0c 100644 --- a/contracts/chain-adapters/interfaces/AdapterInterface.sol +++ b/contracts/chain-adapters/interfaces/AdapterInterface.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/contracts/erc1155/MintableERC1155.sol b/contracts/erc1155/MintableERC1155.sol index 6b568785..7603c9b4 100644 --- a/contracts/erc1155/MintableERC1155.sol +++ b/contracts/erc1155/MintableERC1155.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/contracts/external/interfaces/WETH9Interface.sol b/contracts/external/interfaces/WETH9Interface.sol index d19f6bce..3dcd8d51 100644 --- a/contracts/external/interfaces/WETH9Interface.sol +++ b/contracts/external/interfaces/WETH9Interface.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/contracts/interfaces/HubPoolInterface.sol b/contracts/interfaces/HubPoolInterface.sol index 11db6440..49292e21 100644 --- a/contracts/interfaces/HubPoolInterface.sol +++ b/contracts/interfaces/HubPoolInterface.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/interfaces/LpTokenFactoryInterface.sol b/contracts/interfaces/LpTokenFactoryInterface.sol index 28c0063a..6e8012ff 100644 --- a/contracts/interfaces/LpTokenFactoryInterface.sol +++ b/contracts/interfaces/LpTokenFactoryInterface.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/contracts/interfaces/SpokePoolInterface.sol b/contracts/interfaces/SpokePoolInterface.sol index 6d43bf6c..1ba0edcb 100644 --- a/contracts/interfaces/SpokePoolInterface.sol +++ b/contracts/interfaces/SpokePoolInterface.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/contracts/merkle-distributor/AcrossMerkleDistributor.sol b/contracts/merkle-distributor/AcrossMerkleDistributor.sol index 5f4ff955..f881b838 100644 --- a/contracts/merkle-distributor/AcrossMerkleDistributor.sol +++ b/contracts/merkle-distributor/AcrossMerkleDistributor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol"; diff --git a/contracts/test/AcrossMessageHandlerMock.sol b/contracts/test/AcrossMessageHandlerMock.sol index d2a3a436..f2eb6e84 100644 --- a/contracts/test/AcrossMessageHandlerMock.sol +++ b/contracts/test/AcrossMessageHandlerMock.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../SpokePool.sol"; diff --git a/contracts/test/ArbitrumMocks.sol b/contracts/test/ArbitrumMocks.sol index 43a87bb8..b80229ab 100644 --- a/contracts/test/ArbitrumMocks.sol +++ b/contracts/test/ArbitrumMocks.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; contract ArbitrumMockErc20GatewayRouter { diff --git a/contracts/test/MerkleLibTest.sol b/contracts/test/MerkleLibTest.sol index ca3352ef..efc9228b 100644 --- a/contracts/test/MerkleLibTest.sol +++ b/contracts/test/MerkleLibTest.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../MerkleLib.sol"; diff --git a/contracts/test/MockBedrockStandardBridge.sol b/contracts/test/MockBedrockStandardBridge.sol index 747e59d4..8e712628 100644 --- a/contracts/test/MockBedrockStandardBridge.sol +++ b/contracts/test/MockBedrockStandardBridge.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../Ovm_SpokePool.sol"; diff --git a/contracts/test/MockOptimism_SpokePool.sol b/contracts/test/MockOptimism_SpokePool.sol index e8fcf665..0ca6f8dc 100644 --- a/contracts/test/MockOptimism_SpokePool.sol +++ b/contracts/test/MockOptimism_SpokePool.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../Ovm_SpokePool.sol"; diff --git a/contracts/test/PolygonERC20Test.sol b/contracts/test/PolygonERC20Test.sol index 07b439ab..a0b3d8b1 100644 --- a/contracts/test/PolygonERC20Test.sol +++ b/contracts/test/PolygonERC20Test.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@uma/core/contracts/common/implementation/ExpandedERC20.sol"; diff --git a/contracts/test/PolygonMocks.sol b/contracts/test/PolygonMocks.sol index 8c8a73e5..69fbf567 100644 --- a/contracts/test/PolygonMocks.sol +++ b/contracts/test/PolygonMocks.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/contracts/test/SuccinctMocks.sol b/contracts/test/SuccinctMocks.sol index 9ec3fb87..b3f4365b 100644 --- a/contracts/test/SuccinctMocks.sol +++ b/contracts/test/SuccinctMocks.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; contract TelepathyBroadcasterMock { diff --git a/contracts/upgradeable/EIP712CrossChainUpgradeable.sol b/contracts/upgradeable/EIP712CrossChainUpgradeable.sol index 4da8f8e2..7007f61a 100644 --- a/contracts/upgradeable/EIP712CrossChainUpgradeable.sol +++ b/contracts/upgradeable/EIP712CrossChainUpgradeable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; diff --git a/contracts/upgradeable/MultiCallerUpgradeable.sol b/contracts/upgradeable/MultiCallerUpgradeable.sol index 083a6b95..d907dbf1 100644 --- a/contracts/upgradeable/MultiCallerUpgradeable.sol +++ b/contracts/upgradeable/MultiCallerUpgradeable.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** diff --git a/deployments/arbitrum-goerli/Arbitrum_SpokePool.json b/deployments/arbitrum-goerli/Arbitrum_SpokePool.json index 3f196dfa..3b51974c 100644 --- a/deployments/arbitrum-goerli/Arbitrum_SpokePool.json +++ b/deployments/arbitrum-goerli/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "2703c51b0457010edb5371429c04306b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200482a3803806200482a8339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b60805161452162000309600039600081816101e401528181610dd001528181610e990152818161237e01528181612d2c0152612d8201526145216000f3fe6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json b/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json index 08b2be5e..53154379 100644 --- a/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json +++ b/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,46 +119,46 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -167,22 +167,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json b/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json index 695cae39..dca93736 100644 --- a/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json +++ b/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundRoot().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayRoot().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit ETH if the originToken is WETH and this function will handle wrapping ETH.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // This array is grouped with the two above, and it represents the amount to send or request back from the\\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\\n // bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 requestExpirationTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0x71b427ffd4a1e8c0cc681bafe050c536d79464f12559e90172681e6745f2e7bc\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\\n // instruct this contract to wrap ETH when depositing.\\n WETH9 public immutable weth;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n bytes32 indexed relayHash,\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n weth = WETH9(_wethAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundRoot().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayRoot().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\\n * function will handle wrapping ETH.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\\n if (originToken == address(weth) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n weth.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n numberOfDeposits += 1;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayRoot(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(crossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(hubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(weth)).safeTransfer(to, amount);\\n } else {\\n weth.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is weth then unwrap and send eth.\\n if (relayData.destinationToken == address(weth)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 relayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayHash,\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x460bea0562b87af55699b2ec0e53735b2224039573f9c5243815541263588bc1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe0ae593c1cd9c8204f0b7a3f226a5d4bd30d580692d2ecb2a33548b5b4e75f12\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundRoot().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayRoot().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit ETH if the originToken is WETH and this function will handle wrapping ETH.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // This array is grouped with the two above, and it represents the amount to send or request back from the\\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\\n // bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 requestExpirationTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0x71b427ffd4a1e8c0cc681bafe050c536d79464f12559e90172681e6745f2e7bc\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\\n // instruct this contract to wrap ETH when depositing.\\n WETH9 public immutable weth;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n bytes32 indexed relayHash,\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n weth = WETH9(_wethAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundRoot().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayRoot().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\\n * function will handle wrapping ETH.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\\n if (originToken == address(weth) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n weth.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n numberOfDeposits += 1;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayRoot(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(crossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(hubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(weth)).safeTransfer(to, amount);\\n } else {\\n weth.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is weth then unwrap and send eth.\\n if (relayData.destinationToken == address(weth)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 relayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayHash,\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x460bea0562b87af55699b2ec0e53735b2224039573f9c5243815541263588bc1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe0ae593c1cd9c8204f0b7a3f226a5d4bd30d580692d2ecb2a33548b5b4e75f12\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004831380380620048318339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b608051614528620003096000396000818161030001528181610d4c01528181610e1501528181611fcf01528181612a5f0152612ab501526145286000f3fe6080604052600436106101c65760003560e01c806389a153cc116100f7578063daf9c21011610095578063ee2a53f811610064578063ee2a53f8146105e0578063f06850f614610615578063f500697c14610642578063ffc351a31461066257600080fd5b8063daf9c21014610530578063de7eba7814610573578063e190440214610593578063e282d5b9146105c057600080fd5b8063a1244c67116100d1578063a1244c671461048a578063ac9650d8146104c3578063c8356859146104e3578063c894c0ca1461051057600080fd5b806389a153cc146104375780638a7860ce146104575780639a8a05921461047757600080fd5b80633fc8cef3116101645780634e3485c81161013e5780634e3485c8146103555780635249fef1146103755780635285e058146103c057806357f6dcb8146103ed57600080fd5b80633fc8cef3146102ee5780634922897814610322578063493a4f841461033557600080fd5b8063272751c7116101a0578063272751c71461026b5780632752042e1461028b57806329cb924d146102ab578063364f01a6146102ce57600080fd5b80631c39c38d146101d25780631dfb2d021461022957806322f8e5661461024b57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506000546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023557600080fd5b50610249610244366004613629565b610682565b005b34801561025757600080fd5b50610249610266366004613644565b61070f565b34801561027757600080fd5b5061024961028636600461366b565b6107b8565b34801561029757600080fd5b506102496102a63660046136bf565b6108cf565b3480156102b757600080fd5b506102c06109d0565b604051908152602001610220565b3480156102da57600080fd5b506102496102e93660046136da565b610a88565b3480156102fa57600080fd5b506101ff7f000000000000000000000000000000000000000000000000000000000000000081565b610249610330366004613725565b610b17565b34801561034157600080fd5b5061024961035036600461378b565b610f7e565b34801561036157600080fd5b50610249610370366004613629565b6110a1565b34801561038157600080fd5b506103b06103903660046137ad565b600360209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610220565b3480156103cc57600080fd5b506001546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506002546104229074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610220565b34801561044357600080fd5b506102496104523660046137d7565b6110e7565b34801561046357600080fd5b50610249610472366004613644565b611243565b34801561048357600080fd5b50466102c0565b34801561049657600080fd5b50600254610422907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104d66104d1366004613875565b611317565b6040516102209190613960565b3480156104ef57600080fd5b506006546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561051c57600080fd5b5061024961052b366004613b78565b6114f1565b34801561053c57600080fd5b506101ff61054b366004613629565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b5061024961058e366004613629565b611575565b34801561059f57600080fd5b506002546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105cc57600080fd5b506102496105db366004613d0b565b6115bb565b3480156105ec57600080fd5b506106006105fb366004613644565b611719565b60408051928352602083019190915201610220565b34801561062157600080fd5b506102c0610630366004613644565b60056020526000908152604090205481565b34801561064e57600080fd5b5061024961065d366004613d7a565b611747565b34801561066e57600080fd5b5061024961067d366004613e41565b6117d3565b61068a61193e565b610692611a0a565b6106bf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611a8e565b61070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661073157600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561079d57600080fd5b505af11580156107b1573d6000803e3d6000fd5b5050505050565b6107c061193e565b6107c8611a0a565b6107f5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260036020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108d761193e565b6108df611a0a565b61090c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610a835760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7e9190613f1f565b905090565b504290565b610a9061193e565b610a98611a0a565b610ac5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610acf8282611b7a565b610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610b1f611a0a565b610b4c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832086845290915290205460ff16610beb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b600254610c919074010000000000000000000000000000000000000000900463ffffffff1682613f67565b63ffffffff16610c9f6109d0565b10158015610ce45750600254610cd39074010000000000000000000000000000000000000000900463ffffffff1682613f8c565b63ffffffff16610ce16109d0565b11155b610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610da55750600034115b15610e9957833414610e13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b5050505050610ebb565b610ebb73ffffffffffffffffffffffffffffffffffffffff8616333087611bf6565b610ef28446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611cd2565b6001600260188282829054906101000a900463ffffffff16610f149190613f8c565b92506101000a81548163ffffffff021916908363ffffffff160217905550610f76600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f8661193e565b610f8e611a0a565b610fbb600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60048054600181018255600091909152600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018490557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01828155604080518581526020810185905263ffffffff8416917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af910160405180910390a25050610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6110a961193e565b6110b1611a0a565b6110de600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611d63565b6110ef611a0a565b61111c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111914690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111cd82611dd2565b905060006111df82848b886000611e02565b90506111f082828a888760006120af565b505050611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61124b61193e565b611253611a0a565b611280600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6004818154811061129357611293613fb4565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610be2565b8167ffffffffffffffff81111561139a5761139a6139e0565b6040519080825280602002602001820160405280156113cd57816020015b60608152602001906001900390816113b85790505b50905060005b828110156114ea57600080308686858181106113f1576113f1613fb4565b90506020028101906114039190613fe3565b604051611411929190614048565b600060405180830381855af49150503d806000811461144c576040519150601f19603f3d011682016040523d82523d6000602084013e611451565b606091505b5091509150816114b75760448151101561146a57600080fd5b600481019050808060200190518101906114849190614088565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b808484815181106114ca576114ca613fb4565b6020026020010181905250505080806114e2906140e4565b9150506113d3565b5092915050565b6114f9611a0a565b611526600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115318383836121e4565b6108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61157d61193e565b611585611a0a565b6115b2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c8816125aa565b6115c3611a0a565b6115f0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b6116788446858585612696565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116c792919061411c565b60405180910390a3611713600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6004818154811061172957600080fd5b60009182526020909120600390910201805460019091015490915082565b61174f611a0a565b61177c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61178f8a8a8a8a8a468b8b8b8b8b612733565b611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6117db611a0a565b611808600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118158c87858585612696565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188a4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c682611dd2565b905060006118d882848d896000611e02565b90506118e982828c898760006120af565b505050611930600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b6001546119749073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610be2565b565b60005474010000000000000000000000000000000000000000900460ff16611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be2565b73ffffffffffffffffffffffffffffffffffffffff8116611b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610be2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117139085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526128b2565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001611de5919061413f565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff16108015611e3a57506706f05b59d3b200008560c0015167ffffffffffffffff16105b611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610be2565b606085015160008781526005602052604090205410611f1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610be2565b83600003611f2b575060006120a6565b611f4484848760c00151611f3f91906141e6565b6129be565b60008781526005602052604081205460608801519293508692611f679190614209565b905082811015611f9057809250611f8d83868960c00151611f8891906141e6565b6129ff565b91505b60008881526005602052604081208054859290611fae908490614220565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361203657836120235760408701516120239073ffffffffffffffffffffffffffffffffffffffff16333085611bf6565b612031876020015183612a28565b6120a3565b8361207057612031338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611bf6909392919063ffffffff16565b6120a3876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f6040516121d49c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b46826020015114612251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610be2565b8160400151518260a0015151146122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610be2565b600060048463ffffffff16815481106122df576122df613fb4565b906000526020600020906003020190506122fe81600101548484612bbf565b612364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610be2565b61237b81600201846060015163ffffffff16612bfa565b156123e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610be2565b6123f981600201846060015163ffffffff16612c3b565b60005b8360400151518163ffffffff1610156124a557600084604001518263ffffffff168151811061242d5761242d613fb4565b602002602001015190506000811115612492576124928560a001518363ffffffff168151811061245f5761245f613fb4565b602002602001015182876080015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b508061249d81614238565b9150506123fc565b5082511561253e576124b683612c79565b826080015173ffffffffffffffffffffffffffffffffffffffff16836060015163ffffffff1684602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f7186600001513360405161253592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b826060015163ffffffff168463ffffffff1684602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8660000151876040015188608001518960a001513360405161259c9594939291906142dc565b60405180910390a450505050565b73ffffffffffffffffffffffffffffffffffffffff8116612627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610be2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061271d82612e45565b905061272a878285612e80565b50505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061280860048463ffffffff16815481106127ef576127ef613fb4565b9060005260206000209060030201600001548284612f1e565b61286e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610be2565b600061287982611dd2565b905060006128908284856060015160006001611e02565b90506128a282826000808760016120af565b5050505050505050505050505050565b6000612914826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f369092919063ffffffff16565b8051909150156108ca5780806020019051810190612932919061433a565b6108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610be2565b60006129d282670de0b6b3a7640000614357565b67ffffffffffffffff166129ee84670de0b6b3a7640000614378565b6129f891906143e4565b9392505050565b6000670de0b6b3a7640000612a148382614357565b6129ee9067ffffffffffffffff1685614378565b73ffffffffffffffffffffffffffffffffffffffff82163b15612a8657610b1373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612b69565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b0e57600080fd5b505af1158015612b22573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ca573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ca9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c50565b6000612bf2828585604051602001612bd791906143f8565b60405160208183030381529060405280519060200120612f45565b949350505050565b600080612c09610100846143e4565b90506000612c1961010085614493565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c49610100836143e4565b90506000612c5961010084614493565b600092835260209490945250604090208054600190931b90921790915550565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612d0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610be2565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612da1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612de79190810190614088565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01611de5565b612e8a8282612f5b565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610be2565b6000612bf2828585604051602001612bd7919061413f565b6060612bf28484600085612f7f565b600082612f528584613115565b14949350505050565b6000806000612f6a8585613181565b91509150612f77816131ef565b509392505050565b606082471015613011576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610be2565b73ffffffffffffffffffffffffffffffffffffffff85163b61308f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610be2565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516130b891906144a7565b60006040518083038185875af1925050503d80600081146130f5576040519150601f19603f3d011682016040523d82523d6000602084013e6130fa565b606091505b509150915061310a828286613443565b979650505050505050565b600081815b8451811015612f7757600085828151811061313757613137613fb4565b6020026020010151905080831161315d576000838152602082905260409020925061316e565b600081815260208490526040902092505b5080613179816140e4565b91505061311a565b60008082516041036131b75760208301516040840151606085015160001a6131ab87828585613496565b945094505050506131e8565b82516040036131e057602083015160408401516131d58683836135ae565b9350935050506131e8565b506000905060025b9250929050565b6000816004811115613203576132036144c3565b0361320b5750565b600181600481111561321f5761321f6144c3565b03613286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610be2565b600281600481111561329a5761329a6144c3565b03613301576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610be2565b6003816004811115613315576133156144c3565b036133a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b60048160048111156133b6576133b66144c3565b0361070c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b606083156134525750816129f8565b8251156134625782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134cd57506000905060036135a5565b8460ff16601b141580156134e557508460ff16601c14155b156134f657506000905060046135a5565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561354a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661359e576000600192509250506135a5565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135e460ff86901c601b614220565b90506135f287828885613496565b935093505050935093915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461362457600080fd5b919050565b60006020828403121561363b57600080fd5b6129f882613600565b60006020828403121561365657600080fd5b5035919050565b801515811461070c57600080fd5b60008060006060848603121561368057600080fd5b61368984613600565b92506020840135915060408401356136a08161365d565b809150509250925092565b803563ffffffff8116811461362457600080fd5b6000602082840312156136d157600080fd5b6129f8826136ab565b600080604083850312156136ed57600080fd5b6136f683613600565b915061370460208401613600565b90509250929050565b803567ffffffffffffffff8116811461362457600080fd5b60008060008060008060c0878903121561373e57600080fd5b61374787613600565b955061375560208801613600565b945060408701359350606087013592506137716080880161370d565b915061377f60a088016136ab565b90509295509295509295565b6000806040838503121561379e57600080fd5b50508035926020909101359150565b600080604083850312156137c057600080fd5b6137c983613600565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156137f757600080fd5b6138008b613600565b995061380e60208c01613600565b985061381c60408c01613600565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061384660e08c0161370d565b92506138556101008c0161370d565b91506138646101208c016136ab565b90509295989b9194979a5092959850565b6000806020838503121561388857600080fd5b823567ffffffffffffffff808211156138a057600080fd5b818501915085601f8301126138b457600080fd5b8135818111156138c357600080fd5b8660208260051b85010111156138d857600080fd5b60209290920196919550909350505050565b60005b838110156139055781810151838201526020016138ed565b838111156117135750506000910152565b6000815180845261392e8160208601602086016138ea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139c1858351613916565b94509285019290850190600101613987565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a3257613a326139e0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7f57613a7f6139e0565b604052919050565b600067ffffffffffffffff821115613aa157613aa16139e0565b5060051b60200190565b600082601f830112613abc57600080fd5b81356020613ad1613acc83613a87565b613a38565b82815260059290921b84018101918181019086841115613af057600080fd5b8286015b84811015613b0b5780358352918301918301613af4565b509695505050505050565b600082601f830112613b2757600080fd5b81356020613b37613acc83613a87565b82815260059290921b84018101918181019086841115613b5657600080fd5b8286015b84811015613b0b57613b6b81613600565b8352918301918301613b5a565b600080600060608486031215613b8d57600080fd5b613b96846136ab565b9250602084013567ffffffffffffffff80821115613bb357600080fd5b9085019060c08288031215613bc757600080fd5b613bcf613a0f565b8235815260208301356020820152604083013582811115613bef57600080fd5b613bfb89828601613aab565b604083015250613c0d606084016136ab565b6060820152613c1e60808401613600565b608082015260a083013582811115613c3557600080fd5b613c4189828601613b16565b60a08301525093506040860135915080821115613c5d57600080fd5b50613c6a86828701613aab565b9150509250925092565b600067ffffffffffffffff821115613c8e57613c8e6139e0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613ccb57600080fd5b8135613cd9613acc82613c74565b818152846020838601011115613cee57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d2157600080fd5b613d2a85613600565b9350613d386020860161370d565b9250613d46604086016136ab565b9150606085013567ffffffffffffffff811115613d6257600080fd5b613d6e87828801613cba565b91505092959194509250565b6000806000806000806000806000806101408b8d031215613d9a57600080fd5b613da38b613600565b9950613db160208c01613600565b9850613dbf60408c01613600565b975060608b0135965060808b01359550613ddb60a08c0161370d565b9450613de960c08c0161370d565b9350613df760e08c016136ab565b9250613e066101008c016136ab565b91506101208b013567ffffffffffffffff811115613e2357600080fd5b613e2f8d828e01613aab565b9150509295989b9194979a5092959850565b6000806000806000806000806000806000806101808d8f031215613e6457600080fd5b613e6d8d613600565b9b50613e7b60208e01613600565b9a50613e8960408e01613600565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613eb360e08e0161370d565b9450613ec26101008e0161370d565b9350613ed16101208e0161370d565b9250613ee06101408e016136ab565b915067ffffffffffffffff6101608e01351115613efc57600080fd5b613f0d8e6101608f01358f01613cba565b90509295989b509295989b509295989b565b600060208284031215613f3157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f8457613f84613f38565b039392505050565b600063ffffffff808316818516808303821115613fab57613fab613f38565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261401857600080fd5b83018035915067ffffffffffffffff82111561403357600080fd5b6020019150368190038213156131e857600080fd5b8183823760009101908152919050565b6000614066613acc84613c74565b905082815283838301111561407a57600080fd5b6129f88360208301846138ea565b60006020828403121561409a57600080fd5b815167ffffffffffffffff8111156140b157600080fd5b8201601f810184136140c257600080fd5b612bf284825160208401614058565b6020815260006129f86020830184613916565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361411557614115613f38565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf26040830184613916565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516141b460c084018267ffffffffffffffff169052565b5060e08301516141d060e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613fab57613fab613f38565b60008282101561421b5761421b613f38565b500390565b6000821982111561423357614233613f38565b500190565b600063ffffffff80831681810361425157614251613f38565b6001019392505050565b600081518084526020808501945080840160005b8381101561428b5781518752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b8381101561428b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016142aa565b85815260a0602082015260006142f560a083018761425b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526143248287614296565b9250808516608085015250509695505050505050565b60006020828403121561434c57600080fd5b81516129f88161365d565b600067ffffffffffffffff83811690831681811015613f8457613f84613f38565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156143b0576143b0613f38565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826143f3576143f36143b5565b500490565b6020815281516020820152602082015160408201526000604083015160c0606084015261442860e084018261425b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526120a68282614296565b6000826144a2576144a26143b5565b500690565b600082516144b98184602087016138ea565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212200366289a2afa53961ee89e12be7aa19d0583eb8987acfd894558f08599d1737364736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806389a153cc116100f7578063daf9c21011610095578063ee2a53f811610064578063ee2a53f8146105e0578063f06850f614610615578063f500697c14610642578063ffc351a31461066257600080fd5b8063daf9c21014610530578063de7eba7814610573578063e190440214610593578063e282d5b9146105c057600080fd5b8063a1244c67116100d1578063a1244c671461048a578063ac9650d8146104c3578063c8356859146104e3578063c894c0ca1461051057600080fd5b806389a153cc146104375780638a7860ce146104575780639a8a05921461047757600080fd5b80633fc8cef3116101645780634e3485c81161013e5780634e3485c8146103555780635249fef1146103755780635285e058146103c057806357f6dcb8146103ed57600080fd5b80633fc8cef3146102ee5780634922897814610322578063493a4f841461033557600080fd5b8063272751c7116101a0578063272751c71461026b5780632752042e1461028b57806329cb924d146102ab578063364f01a6146102ce57600080fd5b80631c39c38d146101d25780631dfb2d021461022957806322f8e5661461024b57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506000546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023557600080fd5b50610249610244366004613629565b610682565b005b34801561025757600080fd5b50610249610266366004613644565b61070f565b34801561027757600080fd5b5061024961028636600461366b565b6107b8565b34801561029757600080fd5b506102496102a63660046136bf565b6108cf565b3480156102b757600080fd5b506102c06109d0565b604051908152602001610220565b3480156102da57600080fd5b506102496102e93660046136da565b610a88565b3480156102fa57600080fd5b506101ff7f000000000000000000000000000000000000000000000000000000000000000081565b610249610330366004613725565b610b17565b34801561034157600080fd5b5061024961035036600461378b565b610f7e565b34801561036157600080fd5b50610249610370366004613629565b6110a1565b34801561038157600080fd5b506103b06103903660046137ad565b600360209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610220565b3480156103cc57600080fd5b506001546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506002546104229074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610220565b34801561044357600080fd5b506102496104523660046137d7565b6110e7565b34801561046357600080fd5b50610249610472366004613644565b611243565b34801561048357600080fd5b50466102c0565b34801561049657600080fd5b50600254610422907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104d66104d1366004613875565b611317565b6040516102209190613960565b3480156104ef57600080fd5b506006546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561051c57600080fd5b5061024961052b366004613b78565b6114f1565b34801561053c57600080fd5b506101ff61054b366004613629565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b5061024961058e366004613629565b611575565b34801561059f57600080fd5b506002546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105cc57600080fd5b506102496105db366004613d0b565b6115bb565b3480156105ec57600080fd5b506106006105fb366004613644565b611719565b60408051928352602083019190915201610220565b34801561062157600080fd5b506102c0610630366004613644565b60056020526000908152604090205481565b34801561064e57600080fd5b5061024961065d366004613d7a565b611747565b34801561066e57600080fd5b5061024961067d366004613e41565b6117d3565b61068a61193e565b610692611a0a565b6106bf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611a8e565b61070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661073157600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561079d57600080fd5b505af11580156107b1573d6000803e3d6000fd5b5050505050565b6107c061193e565b6107c8611a0a565b6107f5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260036020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108d761193e565b6108df611a0a565b61090c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610a835760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7e9190613f1f565b905090565b504290565b610a9061193e565b610a98611a0a565b610ac5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610acf8282611b7a565b610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610b1f611a0a565b610b4c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832086845290915290205460ff16610beb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b600254610c919074010000000000000000000000000000000000000000900463ffffffff1682613f67565b63ffffffff16610c9f6109d0565b10158015610ce45750600254610cd39074010000000000000000000000000000000000000000900463ffffffff1682613f8c565b63ffffffff16610ce16109d0565b11155b610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610da55750600034115b15610e9957833414610e13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b5050505050610ebb565b610ebb73ffffffffffffffffffffffffffffffffffffffff8616333087611bf6565b610ef28446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611cd2565b6001600260188282829054906101000a900463ffffffff16610f149190613f8c565b92506101000a81548163ffffffff021916908363ffffffff160217905550610f76600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f8661193e565b610f8e611a0a565b610fbb600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60048054600181018255600091909152600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018490557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01828155604080518581526020810185905263ffffffff8416917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af910160405180910390a25050610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6110a961193e565b6110b1611a0a565b6110de600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611d63565b6110ef611a0a565b61111c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111914690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111cd82611dd2565b905060006111df82848b886000611e02565b90506111f082828a888760006120af565b505050611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61124b61193e565b611253611a0a565b611280600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6004818154811061129357611293613fb4565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610be2565b8167ffffffffffffffff81111561139a5761139a6139e0565b6040519080825280602002602001820160405280156113cd57816020015b60608152602001906001900390816113b85790505b50905060005b828110156114ea57600080308686858181106113f1576113f1613fb4565b90506020028101906114039190613fe3565b604051611411929190614048565b600060405180830381855af49150503d806000811461144c576040519150601f19603f3d011682016040523d82523d6000602084013e611451565b606091505b5091509150816114b75760448151101561146a57600080fd5b600481019050808060200190518101906114849190614088565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b808484815181106114ca576114ca613fb4565b6020026020010181905250505080806114e2906140e4565b9150506113d3565b5092915050565b6114f9611a0a565b611526600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115318383836121e4565b6108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61157d61193e565b611585611a0a565b6115b2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c8816125aa565b6115c3611a0a565b6115f0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b6116788446858585612696565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116c792919061411c565b60405180910390a3611713600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6004818154811061172957600080fd5b60009182526020909120600390910201805460019091015490915082565b61174f611a0a565b61177c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61178f8a8a8a8a8a468b8b8b8b8b612733565b611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6117db611a0a565b611808600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118158c87858585612696565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188a4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c682611dd2565b905060006118d882848d896000611e02565b90506118e982828c898760006120af565b505050611930600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b6001546119749073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610be2565b565b60005474010000000000000000000000000000000000000000900460ff16611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be2565b73ffffffffffffffffffffffffffffffffffffffff8116611b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610be2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117139085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526128b2565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001611de5919061413f565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff16108015611e3a57506706f05b59d3b200008560c0015167ffffffffffffffff16105b611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610be2565b606085015160008781526005602052604090205410611f1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610be2565b83600003611f2b575060006120a6565b611f4484848760c00151611f3f91906141e6565b6129be565b60008781526005602052604081205460608801519293508692611f679190614209565b905082811015611f9057809250611f8d83868960c00151611f8891906141e6565b6129ff565b91505b60008881526005602052604081208054859290611fae908490614220565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361203657836120235760408701516120239073ffffffffffffffffffffffffffffffffffffffff16333085611bf6565b612031876020015183612a28565b6120a3565b8361207057612031338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611bf6909392919063ffffffff16565b6120a3876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f6040516121d49c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b46826020015114612251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610be2565b8160400151518260a0015151146122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610be2565b600060048463ffffffff16815481106122df576122df613fb4565b906000526020600020906003020190506122fe81600101548484612bbf565b612364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610be2565b61237b81600201846060015163ffffffff16612bfa565b156123e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610be2565b6123f981600201846060015163ffffffff16612c3b565b60005b8360400151518163ffffffff1610156124a557600084604001518263ffffffff168151811061242d5761242d613fb4565b602002602001015190506000811115612492576124928560a001518363ffffffff168151811061245f5761245f613fb4565b602002602001015182876080015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b508061249d81614238565b9150506123fc565b5082511561253e576124b683612c79565b826080015173ffffffffffffffffffffffffffffffffffffffff16836060015163ffffffff1684602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f7186600001513360405161253592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b826060015163ffffffff168463ffffffff1684602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8660000151876040015188608001518960a001513360405161259c9594939291906142dc565b60405180910390a450505050565b73ffffffffffffffffffffffffffffffffffffffff8116612627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610be2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061271d82612e45565b905061272a878285612e80565b50505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061280860048463ffffffff16815481106127ef576127ef613fb4565b9060005260206000209060030201600001548284612f1e565b61286e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610be2565b600061287982611dd2565b905060006128908284856060015160006001611e02565b90506128a282826000808760016120af565b5050505050505050505050505050565b6000612914826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f369092919063ffffffff16565b8051909150156108ca5780806020019051810190612932919061433a565b6108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610be2565b60006129d282670de0b6b3a7640000614357565b67ffffffffffffffff166129ee84670de0b6b3a7640000614378565b6129f891906143e4565b9392505050565b6000670de0b6b3a7640000612a148382614357565b6129ee9067ffffffffffffffff1685614378565b73ffffffffffffffffffffffffffffffffffffffff82163b15612a8657610b1373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612b69565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b0e57600080fd5b505af1158015612b22573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ca573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ca9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c50565b6000612bf2828585604051602001612bd791906143f8565b60405160208183030381529060405280519060200120612f45565b949350505050565b600080612c09610100846143e4565b90506000612c1961010085614493565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c49610100836143e4565b90506000612c5961010084614493565b600092835260209490945250604090208054600190931b90921790915550565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612d0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610be2565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612da1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612de79190810190614088565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01611de5565b612e8a8282612f5b565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610be2565b6000612bf2828585604051602001612bd7919061413f565b6060612bf28484600085612f7f565b600082612f528584613115565b14949350505050565b6000806000612f6a8585613181565b91509150612f77816131ef565b509392505050565b606082471015613011576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610be2565b73ffffffffffffffffffffffffffffffffffffffff85163b61308f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610be2565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516130b891906144a7565b60006040518083038185875af1925050503d80600081146130f5576040519150601f19603f3d011682016040523d82523d6000602084013e6130fa565b606091505b509150915061310a828286613443565b979650505050505050565b600081815b8451811015612f7757600085828151811061313757613137613fb4565b6020026020010151905080831161315d576000838152602082905260409020925061316e565b600081815260208490526040902092505b5080613179816140e4565b91505061311a565b60008082516041036131b75760208301516040840151606085015160001a6131ab87828585613496565b945094505050506131e8565b82516040036131e057602083015160408401516131d58683836135ae565b9350935050506131e8565b506000905060025b9250929050565b6000816004811115613203576132036144c3565b0361320b5750565b600181600481111561321f5761321f6144c3565b03613286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610be2565b600281600481111561329a5761329a6144c3565b03613301576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610be2565b6003816004811115613315576133156144c3565b036133a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b60048160048111156133b6576133b66144c3565b0361070c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b606083156134525750816129f8565b8251156134625782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134cd57506000905060036135a5565b8460ff16601b141580156134e557508460ff16601c14155b156134f657506000905060046135a5565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561354a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661359e576000600192509250506135a5565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135e460ff86901c601b614220565b90506135f287828885613496565b935093505050935093915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461362457600080fd5b919050565b60006020828403121561363b57600080fd5b6129f882613600565b60006020828403121561365657600080fd5b5035919050565b801515811461070c57600080fd5b60008060006060848603121561368057600080fd5b61368984613600565b92506020840135915060408401356136a08161365d565b809150509250925092565b803563ffffffff8116811461362457600080fd5b6000602082840312156136d157600080fd5b6129f8826136ab565b600080604083850312156136ed57600080fd5b6136f683613600565b915061370460208401613600565b90509250929050565b803567ffffffffffffffff8116811461362457600080fd5b60008060008060008060c0878903121561373e57600080fd5b61374787613600565b955061375560208801613600565b945060408701359350606087013592506137716080880161370d565b915061377f60a088016136ab565b90509295509295509295565b6000806040838503121561379e57600080fd5b50508035926020909101359150565b600080604083850312156137c057600080fd5b6137c983613600565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156137f757600080fd5b6138008b613600565b995061380e60208c01613600565b985061381c60408c01613600565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061384660e08c0161370d565b92506138556101008c0161370d565b91506138646101208c016136ab565b90509295989b9194979a5092959850565b6000806020838503121561388857600080fd5b823567ffffffffffffffff808211156138a057600080fd5b818501915085601f8301126138b457600080fd5b8135818111156138c357600080fd5b8660208260051b85010111156138d857600080fd5b60209290920196919550909350505050565b60005b838110156139055781810151838201526020016138ed565b838111156117135750506000910152565b6000815180845261392e8160208601602086016138ea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139c1858351613916565b94509285019290850190600101613987565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a3257613a326139e0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7f57613a7f6139e0565b604052919050565b600067ffffffffffffffff821115613aa157613aa16139e0565b5060051b60200190565b600082601f830112613abc57600080fd5b81356020613ad1613acc83613a87565b613a38565b82815260059290921b84018101918181019086841115613af057600080fd5b8286015b84811015613b0b5780358352918301918301613af4565b509695505050505050565b600082601f830112613b2757600080fd5b81356020613b37613acc83613a87565b82815260059290921b84018101918181019086841115613b5657600080fd5b8286015b84811015613b0b57613b6b81613600565b8352918301918301613b5a565b600080600060608486031215613b8d57600080fd5b613b96846136ab565b9250602084013567ffffffffffffffff80821115613bb357600080fd5b9085019060c08288031215613bc757600080fd5b613bcf613a0f565b8235815260208301356020820152604083013582811115613bef57600080fd5b613bfb89828601613aab565b604083015250613c0d606084016136ab565b6060820152613c1e60808401613600565b608082015260a083013582811115613c3557600080fd5b613c4189828601613b16565b60a08301525093506040860135915080821115613c5d57600080fd5b50613c6a86828701613aab565b9150509250925092565b600067ffffffffffffffff821115613c8e57613c8e6139e0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613ccb57600080fd5b8135613cd9613acc82613c74565b818152846020838601011115613cee57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d2157600080fd5b613d2a85613600565b9350613d386020860161370d565b9250613d46604086016136ab565b9150606085013567ffffffffffffffff811115613d6257600080fd5b613d6e87828801613cba565b91505092959194509250565b6000806000806000806000806000806101408b8d031215613d9a57600080fd5b613da38b613600565b9950613db160208c01613600565b9850613dbf60408c01613600565b975060608b0135965060808b01359550613ddb60a08c0161370d565b9450613de960c08c0161370d565b9350613df760e08c016136ab565b9250613e066101008c016136ab565b91506101208b013567ffffffffffffffff811115613e2357600080fd5b613e2f8d828e01613aab565b9150509295989b9194979a5092959850565b6000806000806000806000806000806000806101808d8f031215613e6457600080fd5b613e6d8d613600565b9b50613e7b60208e01613600565b9a50613e8960408e01613600565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613eb360e08e0161370d565b9450613ec26101008e0161370d565b9350613ed16101208e0161370d565b9250613ee06101408e016136ab565b915067ffffffffffffffff6101608e01351115613efc57600080fd5b613f0d8e6101608f01358f01613cba565b90509295989b509295989b509295989b565b600060208284031215613f3157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f8457613f84613f38565b039392505050565b600063ffffffff808316818516808303821115613fab57613fab613f38565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261401857600080fd5b83018035915067ffffffffffffffff82111561403357600080fd5b6020019150368190038213156131e857600080fd5b8183823760009101908152919050565b6000614066613acc84613c74565b905082815283838301111561407a57600080fd5b6129f88360208301846138ea565b60006020828403121561409a57600080fd5b815167ffffffffffffffff8111156140b157600080fd5b8201601f810184136140c257600080fd5b612bf284825160208401614058565b6020815260006129f86020830184613916565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361411557614115613f38565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf26040830184613916565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516141b460c084018267ffffffffffffffff169052565b5060e08301516141d060e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613fab57613fab613f38565b60008282101561421b5761421b613f38565b500390565b6000821982111561423357614233613f38565b500190565b600063ffffffff80831681810361425157614251613f38565b6001019392505050565b600081518084526020808501945080840160005b8381101561428b5781518752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b8381101561428b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016142aa565b85815260a0602082015260006142f560a083018761425b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526143248287614296565b9250808516608085015250509695505050505050565b60006020828403121561434c57600080fd5b81516129f88161365d565b600067ffffffffffffffff83811690831681811015613f8457613f84613f38565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156143b0576143b0613f38565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826143f3576143f36143b5565b500490565b6020815281516020820152602082015160408201526000604083015160c0606084015261442860e084018261425b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526120a68282614296565b6000826144a2576144a26143b5565b500690565b600082516144b98184602087016138ea565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212200366289a2afa53961ee89e12be7aa19d0583eb8987acfd894558f08599d1737364736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json b/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json index dfb09219..c559e7d2 100644 --- a/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json +++ b/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 chainId_;\n\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {}\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {}\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"OVM_XCHAIN: messenger contract unauthenticated\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,34 +113,34 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 5_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.1e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 10e9; // 10 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20Gateway;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20Gateway ERC20 gateway contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20Gateway) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20Gateway = _l1ERC20Gateway;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n l1ERC20Gateway.outboundTransfer(l1Token, to, amount, l2GasLimit, l2GasPrice, \"\");\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 5_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.1e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 10e9; // 10 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20Gateway;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20Gateway ERC20 gateway contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20Gateway) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20Gateway = _l1ERC20Gateway;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n l1ERC20Gateway.outboundTransfer(l1Token, to, amount, l2GasLimit, l2GasPrice, \"\");\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -149,25 +149,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/arbitrum/Arbitrum_SpokePool.json b/deployments/arbitrum/Arbitrum_SpokePool.json index 9ef1fd8a..0cb3c206 100644 --- a/deployments/arbitrum/Arbitrum_SpokePool.json +++ b/deployments/arbitrum/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "1a5892b796c4f5bdf21d8cd0d15027f4", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200482a3803806200482a8339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b60805161452162000309600039600081816101e401528181610dd001528181610e990152818161237e01528181612d2c0152612d8201526145216000f3fe6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json b/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json index b2008943..021d97dd 100644 --- a/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json +++ b/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n timerAddress,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n timerAddress,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/boba/Boba_SpokePool.json b/deployments/boba/Boba_SpokePool.json index 00a7c160..32bc45dc 100644 --- a/deployments/boba/Boba_SpokePool.json +++ b/deployments/boba/Boba_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "4d00864cb95f68f23bc763892eeb3451", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Boba SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Boba_SpokePool.sol\":\"Boba_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Boba_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\\r\\n */\\r\\ncontract Boba_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Boba SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x294baa3e6cad689a274156221f025eec942a8115307167c652384200d92b6d11\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Boba SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Boba_SpokePool.sol\":\"Boba_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Boba_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\\r\\n */\\r\\ncontract Boba_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Boba SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x294baa3e6cad689a274156221f025eec942a8115307167c652384200d92b6d11\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b401790553480156200003b57600080fd5b5060405162004c9738038062004c978339810160408190526200005e9162000277565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273420000000000000000000000000000000000000673deaddeaddeaddeaddeaddeaddeaddeaddead00008484848383620000e18462000112565b620000ec83620001b8565b506001600160a01b039081166080529490941660a05250620002c1975050505050505050565b6001600160a01b0381166200016e5760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002105760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000165565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200027257600080fd5b919050565b6000806000606084860312156200028d57600080fd5b62000298846200025a565b9250620002a8602085016200025a565b9150620002b8604085016200025a565b90509250925092565b60805160a05161496a6200032d600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220eb7c71015621a3f0e8435e96b853ec4cb7e61d884a87ee1833c41a0d61e5854664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220eb7c71015621a3f0e8435e96b853ec4cb7e61d884a87ee1833c41a0d61e5854664736f6c634300080d0033", "devdoc": { diff --git a/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json b/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json index 4fc72aca..909d1e83 100644 --- a/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json +++ b/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 9303e25d..43633ef5 100644 --- a/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/goerli/AcrossConfigStore.json b/deployments/goerli/AcrossConfigStore.json index 938dc2bc..52bc7404 100644 --- a/deployments/goerli/AcrossConfigStore.json +++ b/deployments/goerli/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "e3638a53e1e5b7b0c7a6b5bbdc94b1ad", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbd4b1690b7d56f2fd7b61f3b9022c6b856c7dfee5a5aca547cf1403b906fdc0d\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\n * to be consumed by off-chain bots, rather than by other contracts.\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\n * system of the full contract suite..\\n */\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\n // Transfer Thresholds.\\n mapping(address => string) public l1TokenConfig;\\n\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\n mapping(bytes32 => string) public globalConfig;\\n\\n event UpdatedTokenConfig(address indexed key, string value);\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\n\\n /**\\n * @notice Updates token config.\\n * @param l1Token the l1 token address to update value for.\\n * @param value Value to update.\\n */\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\n l1TokenConfig[l1Token] = value;\\n emit UpdatedTokenConfig(l1Token, value);\\n }\\n\\n /**\\n * @notice Updates global config.\\n * @param key Key to update.\\n * @param value Value to update.\\n */\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\n globalConfig[key] = value;\\n emit UpdatedGlobalConfig(key, value);\\n }\\n}\\n\",\"keccak256\":\"0xacaa65ede2dcee0a24fd5d9940914c364be7e988f89cdaea1386e0474d51f6f7\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbd4b1690b7d56f2fd7b61f3b9022c6b856c7dfee5a5aca547cf1403b906fdc0d\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\n * to be consumed by off-chain bots, rather than by other contracts.\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\n * system of the full contract suite..\\n */\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\n // Transfer Thresholds.\\n mapping(address => string) public l1TokenConfig;\\n\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\n mapping(bytes32 => string) public globalConfig;\\n\\n event UpdatedTokenConfig(address indexed key, string value);\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\n\\n /**\\n * @notice Updates token config.\\n * @param l1Token the l1 token address to update value for.\\n * @param value Value to update.\\n */\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\n l1TokenConfig[l1Token] = value;\\n emit UpdatedTokenConfig(l1Token, value);\\n }\\n\\n /**\\n * @notice Updates global config.\\n * @param key Key to update.\\n * @param value Value to update.\\n */\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\n globalConfig[key] = value;\\n emit UpdatedGlobalConfig(key, value);\\n }\\n}\\n\",\"keccak256\":\"0xacaa65ede2dcee0a24fd5d9940914c364be7e988f89cdaea1386e0474d51f6f7\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080806040523461005b5760008054336001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361100090816100618239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c90816350fbbd011461009a57508063715018a6146100955780638098b875146100905780638da5cb5b1461008b5780639fdd403a14610086578063ac9650d814610081578063e5e818ae1461007c5763f2fde38b1461007757600080fd5b610926565b610729565b6105e0565b610502565b6104b0565b610413565b61033c565b3461010d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d576100fd60406101099273ffffffffffffffffffffffffffffffffffffffff6100ef610110565b168152600160205220610200565b6040519182918261032b565b0390f35b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b600080fd5b90600182811c92168015610181575b602083101461015257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610147565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101fb57604052565b61018b565b6040519081600082549261021384610138565b9081845260019485811690816000146102835750600114610240575b505061023d925003826101ba565b90565b9093915060005260209081600020936000915b81831061026b57505061023d9350820101388061022f565b85548784018501529485019486945091830191610253565b905061023d9550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101388061022f565b60005b8381106102d85750506000910152565b81810151838201526020016102c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610324815180928187528780880191016102c5565b0116010190565b90602061023d9281815201906102e8565b34610133576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d57610374610a5b565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116101fb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761044a610110565b6024359067ffffffffffffffff8211610133573660238301121561013357816004013590610477826103d9565b9161048560405193846101ba565b80835236602482860101116101335760208160009260246104ae97018387013784010152610d5f565b005b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435600052600260205261010961054c6040600020610200565b6040519182916020835260208301906102e8565b602080820190808352835180925260408301928160408460051b8301019501936000915b8483106105945750505050505090565b90919293949584806105d0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a516102e8565b9801930193019194939290610584565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576004803567ffffffffffffffff918282116101335736602383011215610133578181013592831161013357602490818301928236918660051b010111610133576106543415610ada565b61065d84610b57565b9360005b81811061067657604051806101098882610560565b600080610684838589610c49565b60409391610696855180938193610cae565b0390305af4906106a4610cbc565b918290156106d3575050906106ce916106bd8289610d4b565b526106c88188610d4b565b50610bbe565b610661565b868387926044825110610133578261072593856106f69401518301019101610cec565b92519283927f08c379a0000000000000000000000000000000000000000000000000000000008452830161032b565b0390fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335767ffffffffffffffff600435602480358381116101335736602382011215610133578060040135938411610133573682858301011161013357610799610a5b565b60009383855260206002815260408620906107be836107b88454610138565b84610f30565b8690601f841160011461085157509161083e9181867f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f499796958a92610844575b50508260011b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8460031b1c19161790555b6040519384930183610f84565b0390a280f35b86010135905085386107fe565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841661088484600052602060002090565b9289905b82821061090c5750509161083e9391857f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f4998979694106108d2575b5050600182811b019055610831565b867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19918701013516905538806108c3565b80600185968b8395978c0101358155019501930190610888565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761095d610110565b610965610a5b565b73ffffffffffffffffffffffffffffffffffffffff80911680156109d7576000918254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff600054163303610a7c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15610ae157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152fd5b67ffffffffffffffff81116101fb5760051b60200190565b90610b6182610b3f565b610b6e60405191826101ba565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610b9c8294610b3f565b019060005b828110610bad57505050565b806060602080938501015201610ba1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610beb5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015610ca95760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020018236038113610133579190565b610c1a565b908092918237016000815290565b3d15610ce7573d90610ccd826103d9565b91610cdb60405193846101ba565b82523d6000602084013e565b606090565b6020818303126101335780519067ffffffffffffffff8211610133570181601f82011215610133578051610d1f816103d9565b92610d2d60405194856101ba565b818452602082840101116101335761023d91602080850191016102c5565b8051821015610ca95760209160051b010190565b73ffffffffffffffffffffffffffffffffffffffff90610d7d610a5b565b1690816000526001602081815260406000209183519167ffffffffffffffff83116101fb57610db683610db08654610138565b86610f30565b80601f8411600114610e61575091610e31939181807f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd9795600092610e36575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91921b9260031b1c19161790556040519182918261032b565b0390a2565b86015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610df6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084939416610e9686600052602060002090565b926000905b828210610f19575050918391610e3196947f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd98969410610ee2575b5050811b0190556100fd565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880610ed6565b808785968294968c01518155019501930190610e9b565b90601f8111610f3e57505050565b600091825260208220906020601f850160051c83019410610f7a575b601f0160051c01915b828110610f6f57505050565b818155600101610f63565b9092508290610f5a565b90601f836040947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09360208652816020870152868601376000858286010152011601019056fea26469706673582212203c05d8358a45c791a110df40ff71f94d279750050c70155a559409bceaabc4ae64736f6c63430008120033", "deployedBytecode": "0x6080604052600436101561001257600080fd5b6000803560e01c90816350fbbd011461009a57508063715018a6146100955780638098b875146100905780638da5cb5b1461008b5780639fdd403a14610086578063ac9650d814610081578063e5e818ae1461007c5763f2fde38b1461007757600080fd5b610926565b610729565b6105e0565b610502565b6104b0565b610413565b61033c565b3461010d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d576100fd60406101099273ffffffffffffffffffffffffffffffffffffffff6100ef610110565b168152600160205220610200565b6040519182918261032b565b0390f35b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b600080fd5b90600182811c92168015610181575b602083101461015257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610147565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101fb57604052565b61018b565b6040519081600082549261021384610138565b9081845260019485811690816000146102835750600114610240575b505061023d925003826101ba565b90565b9093915060005260209081600020936000915b81831061026b57505061023d9350820101388061022f565b85548784018501529485019486945091830191610253565b905061023d9550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101388061022f565b60005b8381106102d85750506000910152565b81810151838201526020016102c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610324815180928187528780880191016102c5565b0116010190565b90602061023d9281815201906102e8565b34610133576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d57610374610a5b565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116101fb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761044a610110565b6024359067ffffffffffffffff8211610133573660238301121561013357816004013590610477826103d9565b9161048560405193846101ba565b80835236602482860101116101335760208160009260246104ae97018387013784010152610d5f565b005b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435600052600260205261010961054c6040600020610200565b6040519182916020835260208301906102e8565b602080820190808352835180925260408301928160408460051b8301019501936000915b8483106105945750505050505090565b90919293949584806105d0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a516102e8565b9801930193019194939290610584565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576004803567ffffffffffffffff918282116101335736602383011215610133578181013592831161013357602490818301928236918660051b010111610133576106543415610ada565b61065d84610b57565b9360005b81811061067657604051806101098882610560565b600080610684838589610c49565b60409391610696855180938193610cae565b0390305af4906106a4610cbc565b918290156106d3575050906106ce916106bd8289610d4b565b526106c88188610d4b565b50610bbe565b610661565b868387926044825110610133578261072593856106f69401518301019101610cec565b92519283927f08c379a0000000000000000000000000000000000000000000000000000000008452830161032b565b0390fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335767ffffffffffffffff600435602480358381116101335736602382011215610133578060040135938411610133573682858301011161013357610799610a5b565b60009383855260206002815260408620906107be836107b88454610138565b84610f30565b8690601f841160011461085157509161083e9181867f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f499796958a92610844575b50508260011b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8460031b1c19161790555b6040519384930183610f84565b0390a280f35b86010135905085386107fe565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841661088484600052602060002090565b9289905b82821061090c5750509161083e9391857f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f4998979694106108d2575b5050600182811b019055610831565b867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19918701013516905538806108c3565b80600185968b8395978c0101358155019501930190610888565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761095d610110565b610965610a5b565b73ffffffffffffffffffffffffffffffffffffffff80911680156109d7576000918254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff600054163303610a7c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15610ae157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152fd5b67ffffffffffffffff81116101fb5760051b60200190565b90610b6182610b3f565b610b6e60405191826101ba565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610b9c8294610b3f565b019060005b828110610bad57505050565b806060602080938501015201610ba1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610beb5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015610ca95760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020018236038113610133579190565b610c1a565b908092918237016000815290565b3d15610ce7573d90610ccd826103d9565b91610cdb60405193846101ba565b82523d6000602084013e565b606090565b6020818303126101335780519067ffffffffffffffff8211610133570181601f82011215610133578051610d1f816103d9565b92610d2d60405194856101ba565b818452602082840101116101335761023d91602080850191016102c5565b8051821015610ca95760209160051b010190565b73ffffffffffffffffffffffffffffffffffffffff90610d7d610a5b565b1690816000526001602081815260406000209183519167ffffffffffffffff83116101fb57610db683610db08654610138565b86610f30565b80601f8411600114610e61575091610e31939181807f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd9795600092610e36575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91921b9260031b1c19161790556040519182918261032b565b0390a2565b86015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610df6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084939416610e9686600052602060002090565b926000905b828210610f19575050918391610e3196947f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd98969410610ee2575b5050811b0190556100fd565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880610ed6565b808785968294968c01518155019501930190610e9b565b90601f8111610f3e57505050565b600091825260208220906020601f850160051c83019410610f7a575b601f0160051c01915b828110610f6f57505050565b818155600101610f63565b9092508290610f5a565b90601f836040947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09360208652816020870152868601376000858286010152011601019056fea26469706673582212203c05d8358a45c791a110df40ff71f94d279750050c70155a559409bceaabc4ae64736f6c63430008120033", "devdoc": { diff --git a/deployments/goerli/AcrossMerkleDistributor.json b/deployments/goerli/AcrossMerkleDistributor.json index 1b6a0200..f2e062fa 100644 --- a/deployments/goerli/AcrossMerkleDistributor.json +++ b/deployments/goerli/AcrossMerkleDistributor.json @@ -619,7 +619,7 @@ }, "args": [], "solcInputHash": "0c0f7cf4c33344752a752d4aad8f0613", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"ClaimFor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardsDeposited\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"CreatedWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"DeleteWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"WhitelistedClaimer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"WithdrawRewards\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claimFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim[]\",\"name\":\"claims\",\"type\":\"tuple[]\"}],\"name\":\"claimMulti\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"deleteWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"getRewardTokenForWindow\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"}],\"name\":\"isClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"merkleWindows\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"remainingAmount\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCreatedIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rewardsToDeposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"name\":\"setWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"whitelistClaimer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedClaimers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"rewardCurrency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Claim recipient must be equal to msg.sender.\",\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"}},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Caller must be in whitelistedClaimers struct set to \\\"true\\\".\",\"params\":{\"_claim\":\"leaf to claim.\"}},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"details\":\"All claim recipients must be equal to msg.sender.\",\"params\":{\"claims\":\"array of claims to claim.\"}},\"deleteWindow(uint256)\":{\"details\":\"Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\",\"params\":{\"windowIndex\":\"merkle root index to delete.\"}},\"getRewardTokenForWindow(uint256)\":{\"params\":{\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"address Reward token address\"}},\"isClaimed(uint256,uint256)\":{\"details\":\"This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`. The onus is on the Owner of this contract to submit only valid Merkle roots.\",\"params\":{\"accountIndex\":\"account index to check within window index.\",\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"True if claim has been executed already, False otherwise.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setWindow(uint256,address,bytes32,string)\":{\"params\":{\"ipfsHash\":\"hash of IPFS object, conveniently stored for clients\",\"merkleRoot\":\"merkle root describing allocation.\",\"rewardToken\":\"ERC20 reward token.\",\"rewardsToDeposit\":\"amount of rewards to deposit to seed this allocation.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"},\"returns\":{\"valid\":\"True if leaf exists.\"}},\"whitelistClaimer(address,bool)\":{\"details\":\"Callable only by owner.\",\"params\":{\"newContract\":\"Reset claimer contract to this address.\",\"whitelist\":\"True to whitelist claimer, False otherwise.\"}},\"withdrawRewards(address,uint256)\":{\"details\":\"Callable only by owner.\",\"params\":{\"amount\":\"amount of rewards to withdraw.\",\"rewardCurrency\":\"rewards to withdraw from contract.\"}}},\"title\":\"Extended MerkleDistributor contract.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Claim amount of reward tokens for account, as described by Claim input object.\"},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Executes merkle leaf claim on behaf of user. This can only be called by a trusted claimer address. This function is designed to be called atomically with other transactions that ultimately return the claimed amount to the rightful recipient. For example, AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\"},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"notice\":\"Batch claims to reduce gas versus individual submitting all claims. Method will fail if any individual claims within the batch would fail.\"},\"deleteWindow(uint256)\":{\"notice\":\"Delete merkle root at window index.\"},\"getRewardTokenForWindow(uint256)\":{\"notice\":\"Returns rewardToken set by admin for windowIndex.\"},\"isClaimed(uint256,uint256)\":{\"notice\":\"Returns True if the claim for `accountIndex` has already been completed for the Merkle root at `windowIndex`.\"},\"setWindow(uint256,address,bytes32,string)\":{\"notice\":\"Set merkle root for the next available window index and seed allocations.Callable only by owner of this contract. Caller must have approved this contract to transfer `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all claims within the `merkleRoot`.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given window index.\"},\"whitelistClaimer(address,bool)\":{\"notice\":\"Updates whitelisted claimer status.\"},\"withdrawRewards(address,uint256)\":{\"notice\":\"Emergency method that transfers rewards out of the contract if the contract was configured improperly.\"}},\"notice\":\"Adds additional constraints governing who can claim leaves from merkle windows.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":\"AcrossMerkleDistributor\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./MerkleDistributorInterface.sol\\\";\\n\\n/**\\n * Inspired by:\\n * - https://github.com/pie-dao/vested-token-migration-app\\n * - https://github.com/Uniswap/merkle-distributor\\n * - https://github.com/balancer-labs/erc20-redeemable\\n *\\n * @title MerkleDistributor contract.\\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\\n * multiple Merkle roots distributions with customized reward currencies.\\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\\n */\\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\\n using SafeERC20 for IERC20;\\n\\n // Windows are mapped to arbitrary indices.\\n mapping(uint256 => Window) public merkleWindows;\\n\\n // Index of next created Merkle root.\\n uint256 public nextCreatedIndex;\\n\\n // Track which accounts have claimed for each window index.\\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event Claimed(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n event CreatedWindow(\\n uint256 indexed windowIndex,\\n uint256 rewardsDeposited,\\n address indexed rewardToken,\\n address owner\\n );\\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\\n event DeleteWindow(uint256 indexed windowIndex, address owner);\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Set merkle root for the next available window index and seed allocations.\\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\\n * claims within the `merkleRoot`.\\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\\n * @param rewardToken ERC20 reward token.\\n * @param merkleRoot merkle root describing allocation.\\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\\n */\\n function setWindow(\\n uint256 rewardsToDeposit,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string calldata ipfsHash\\n ) external onlyOwner {\\n uint256 indexToSet = nextCreatedIndex;\\n nextCreatedIndex = indexToSet + 1;\\n\\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\\n }\\n\\n /**\\n * @notice Delete merkle root at window index.\\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\\n * @param windowIndex merkle root index to delete.\\n */\\n function deleteWindow(uint256 windowIndex) external onlyOwner {\\n delete merkleWindows[windowIndex];\\n emit DeleteWindow(windowIndex, msg.sender);\\n }\\n\\n /**\\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\\n * @dev Callable only by owner.\\n * @param rewardCurrency rewards to withdraw from contract.\\n * @param amount amount of rewards to withdraw.\\n */\\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\\n rewardCurrency.safeTransfer(msg.sender, amount);\\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public virtual override {\\n uint256 batchedAmount;\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n Claim memory _claim = claims[i];\\n _verifyAndMarkClaimed(_claim);\\n batchedAmount += _claim.amount;\\n\\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\\n uint256 nextI = i + 1;\\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\\n if (\\n nextI == claimCount ||\\n // This claim is last claim.\\n claims[nextI].account != _claim.account ||\\n // Next claim account is different than current one.\\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\\n // Next claim reward token is different than current one.\\n ) {\\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\\n batchedAmount = 0;\\n }\\n }\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public virtual override {\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\\n }\\n\\n /**\\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\\n * `windowIndex`.\\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\\n * @param windowIndex merkle root to check.\\n * @param accountIndex account index to check within window index.\\n * @return True if claim has been executed already, False otherwise.\\n */\\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Returns rewardToken set by admin for windowIndex.\\n * @param windowIndex merkle root to check.\\n * @return address Reward token address\\n */\\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\\n return address(merkleWindows[windowIndex].rewardToken);\\n }\\n\\n /**\\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\\n * window index.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n * @return valid True if leaf exists.\\n */\\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\\n }\\n\\n /****************************\\n * PRIVATE FUNCTIONS\\n ****************************/\\n\\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n claimedBitMap[windowIndex][claimedWordIndex] =\\n claimedBitMap[windowIndex][claimedWordIndex] |\\n (1 << claimedBitIndex);\\n }\\n\\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\\n function _setWindow(\\n uint256 windowIndex,\\n uint256 rewardsDeposited,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string memory ipfsHash\\n ) private {\\n Window storage window = merkleWindows[windowIndex];\\n window.merkleRoot = merkleRoot;\\n window.remainingAmount = rewardsDeposited;\\n window.rewardToken = IERC20(rewardToken);\\n window.ipfsHash = ipfsHash;\\n\\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\\n\\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\\n }\\n\\n // Verify claim is valid and mark it as completed in this contract.\\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\\n // Check claimed proof against merkle window at given index.\\n require(verifyClaim(_claim), \\\"Incorrect merkle proof\\\");\\n // Check the account has not yet claimed for this window.\\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \\\"Account has already claimed for this window\\\");\\n\\n // Proof is correct and claim has not occurred yet, mark claimed complete.\\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\\n emit Claimed(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x45ba14976c04b585ff82098ef0340ae062d9da7a3a2076b2535dbd194d254fc7\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\\n */\\ninterface MerkleDistributorInterface {\\n // A Window maps a Merkle root to a reward token address.\\n struct Window {\\n // Merkle root describing the distribution.\\n bytes32 merkleRoot;\\n // Remaining amount of deposited rewards that have not yet been claimed.\\n uint256 remainingAmount;\\n // Currency in which reward is processed.\\n IERC20 rewardToken;\\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\\n // data type for storing an IPFS hash is a multihash which is the concatenation of \\n // . We opted to store this in a string type to make it easier\\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\\n // go to https://cloudflare-ipfs.com/ipfs/.\\n string ipfsHash;\\n }\\n\\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\\n struct Claim {\\n uint256 windowIndex;\\n uint256 amount;\\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\\n address account;\\n bytes32[] merkleProof;\\n }\\n\\n function claim(Claim memory _claim) external;\\n\\n function claimMulti(Claim[] memory claims) external;\\n\\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\\n}\\n\",\"keccak256\":\"0x0d6527f44b268c3801d45bc1fc6021f22a80070a21d4066430a4d6566e3ff5e7\",\"license\":\"GPL-3.0-only\"},\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title Extended MerkleDistributor contract.\\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\\n */\\ncontract AcrossMerkleDistributor is MerkleDistributor {\\n using SafeERC20 for IERC20;\\n\\n // Addresses that can claim on user's behalf.\\n mapping(address => bool) public whitelistedClaimers;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\\n event ClaimFor(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Updates whitelisted claimer status.\\n * @dev Callable only by owner.\\n * @param newContract Reset claimer contract to this address.\\n * @param whitelist True to whitelist claimer, False otherwise.\\n */\\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\\n whitelistedClaimers[newContract] = whitelist;\\n emit WhitelistedClaimer(newContract, whitelist);\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev All claim recipients must be equal to msg.sender.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public override {\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n require(claims[i].account == msg.sender, \\\"invalid claimer\\\");\\n }\\n super.claimMulti(claims);\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev Claim recipient must be equal to msg.sender.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public override {\\n require(_claim.account == msg.sender, \\\"invalid claimer\\\");\\n super.claim(_claim);\\n }\\n\\n /**\\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\\n * claimer address. This function is designed to be called atomically with other transactions\\n * that ultimately return the claimed amount to the rightful recipient. For example,\\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\\n * @dev Caller must be in whitelistedClaimers struct set to \\\"true\\\".\\n * @param _claim leaf to claim.\\n */\\n\\n function claimFor(Claim memory _claim) public {\\n require(whitelistedClaimers[msg.sender], \\\"unwhitelisted claimer\\\");\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\\n emit ClaimFor(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x770e7f0986351870b1223a1214aaa3084b7cba9f438d7906c62c016ebd11b2c3\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"ClaimFor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardsDeposited\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"CreatedWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"DeleteWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"WhitelistedClaimer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"WithdrawRewards\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claimFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim[]\",\"name\":\"claims\",\"type\":\"tuple[]\"}],\"name\":\"claimMulti\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"deleteWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"getRewardTokenForWindow\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"}],\"name\":\"isClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"merkleWindows\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"remainingAmount\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCreatedIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rewardsToDeposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"name\":\"setWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"whitelistClaimer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedClaimers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"rewardCurrency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Claim recipient must be equal to msg.sender.\",\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"}},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Caller must be in whitelistedClaimers struct set to \\\"true\\\".\",\"params\":{\"_claim\":\"leaf to claim.\"}},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"details\":\"All claim recipients must be equal to msg.sender.\",\"params\":{\"claims\":\"array of claims to claim.\"}},\"deleteWindow(uint256)\":{\"details\":\"Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\",\"params\":{\"windowIndex\":\"merkle root index to delete.\"}},\"getRewardTokenForWindow(uint256)\":{\"params\":{\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"address Reward token address\"}},\"isClaimed(uint256,uint256)\":{\"details\":\"This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`. The onus is on the Owner of this contract to submit only valid Merkle roots.\",\"params\":{\"accountIndex\":\"account index to check within window index.\",\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"True if claim has been executed already, False otherwise.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setWindow(uint256,address,bytes32,string)\":{\"params\":{\"ipfsHash\":\"hash of IPFS object, conveniently stored for clients\",\"merkleRoot\":\"merkle root describing allocation.\",\"rewardToken\":\"ERC20 reward token.\",\"rewardsToDeposit\":\"amount of rewards to deposit to seed this allocation.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"},\"returns\":{\"valid\":\"True if leaf exists.\"}},\"whitelistClaimer(address,bool)\":{\"details\":\"Callable only by owner.\",\"params\":{\"newContract\":\"Reset claimer contract to this address.\",\"whitelist\":\"True to whitelist claimer, False otherwise.\"}},\"withdrawRewards(address,uint256)\":{\"details\":\"Callable only by owner.\",\"params\":{\"amount\":\"amount of rewards to withdraw.\",\"rewardCurrency\":\"rewards to withdraw from contract.\"}}},\"title\":\"Extended MerkleDistributor contract.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Claim amount of reward tokens for account, as described by Claim input object.\"},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Executes merkle leaf claim on behaf of user. This can only be called by a trusted claimer address. This function is designed to be called atomically with other transactions that ultimately return the claimed amount to the rightful recipient. For example, AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\"},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"notice\":\"Batch claims to reduce gas versus individual submitting all claims. Method will fail if any individual claims within the batch would fail.\"},\"deleteWindow(uint256)\":{\"notice\":\"Delete merkle root at window index.\"},\"getRewardTokenForWindow(uint256)\":{\"notice\":\"Returns rewardToken set by admin for windowIndex.\"},\"isClaimed(uint256,uint256)\":{\"notice\":\"Returns True if the claim for `accountIndex` has already been completed for the Merkle root at `windowIndex`.\"},\"setWindow(uint256,address,bytes32,string)\":{\"notice\":\"Set merkle root for the next available window index and seed allocations.Callable only by owner of this contract. Caller must have approved this contract to transfer `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all claims within the `merkleRoot`.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given window index.\"},\"whitelistClaimer(address,bool)\":{\"notice\":\"Updates whitelisted claimer status.\"},\"withdrawRewards(address,uint256)\":{\"notice\":\"Emergency method that transfers rewards out of the contract if the contract was configured improperly.\"}},\"notice\":\"Adds additional constraints governing who can claim leaves from merkle windows.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":\"AcrossMerkleDistributor\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./MerkleDistributorInterface.sol\\\";\\n\\n/**\\n * Inspired by:\\n * - https://github.com/pie-dao/vested-token-migration-app\\n * - https://github.com/Uniswap/merkle-distributor\\n * - https://github.com/balancer-labs/erc20-redeemable\\n *\\n * @title MerkleDistributor contract.\\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\\n * multiple Merkle roots distributions with customized reward currencies.\\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\\n */\\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\\n using SafeERC20 for IERC20;\\n\\n // Windows are mapped to arbitrary indices.\\n mapping(uint256 => Window) public merkleWindows;\\n\\n // Index of next created Merkle root.\\n uint256 public nextCreatedIndex;\\n\\n // Track which accounts have claimed for each window index.\\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event Claimed(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n event CreatedWindow(\\n uint256 indexed windowIndex,\\n uint256 rewardsDeposited,\\n address indexed rewardToken,\\n address owner\\n );\\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\\n event DeleteWindow(uint256 indexed windowIndex, address owner);\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Set merkle root for the next available window index and seed allocations.\\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\\n * claims within the `merkleRoot`.\\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\\n * @param rewardToken ERC20 reward token.\\n * @param merkleRoot merkle root describing allocation.\\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\\n */\\n function setWindow(\\n uint256 rewardsToDeposit,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string calldata ipfsHash\\n ) external onlyOwner {\\n uint256 indexToSet = nextCreatedIndex;\\n nextCreatedIndex = indexToSet + 1;\\n\\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\\n }\\n\\n /**\\n * @notice Delete merkle root at window index.\\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\\n * @param windowIndex merkle root index to delete.\\n */\\n function deleteWindow(uint256 windowIndex) external onlyOwner {\\n delete merkleWindows[windowIndex];\\n emit DeleteWindow(windowIndex, msg.sender);\\n }\\n\\n /**\\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\\n * @dev Callable only by owner.\\n * @param rewardCurrency rewards to withdraw from contract.\\n * @param amount amount of rewards to withdraw.\\n */\\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\\n rewardCurrency.safeTransfer(msg.sender, amount);\\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public virtual override {\\n uint256 batchedAmount;\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n Claim memory _claim = claims[i];\\n _verifyAndMarkClaimed(_claim);\\n batchedAmount += _claim.amount;\\n\\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\\n uint256 nextI = i + 1;\\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\\n if (\\n nextI == claimCount ||\\n // This claim is last claim.\\n claims[nextI].account != _claim.account ||\\n // Next claim account is different than current one.\\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\\n // Next claim reward token is different than current one.\\n ) {\\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\\n batchedAmount = 0;\\n }\\n }\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public virtual override {\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\\n }\\n\\n /**\\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\\n * `windowIndex`.\\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\\n * @param windowIndex merkle root to check.\\n * @param accountIndex account index to check within window index.\\n * @return True if claim has been executed already, False otherwise.\\n */\\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Returns rewardToken set by admin for windowIndex.\\n * @param windowIndex merkle root to check.\\n * @return address Reward token address\\n */\\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\\n return address(merkleWindows[windowIndex].rewardToken);\\n }\\n\\n /**\\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\\n * window index.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n * @return valid True if leaf exists.\\n */\\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\\n }\\n\\n /****************************\\n * PRIVATE FUNCTIONS\\n ****************************/\\n\\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n claimedBitMap[windowIndex][claimedWordIndex] =\\n claimedBitMap[windowIndex][claimedWordIndex] |\\n (1 << claimedBitIndex);\\n }\\n\\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\\n function _setWindow(\\n uint256 windowIndex,\\n uint256 rewardsDeposited,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string memory ipfsHash\\n ) private {\\n Window storage window = merkleWindows[windowIndex];\\n window.merkleRoot = merkleRoot;\\n window.remainingAmount = rewardsDeposited;\\n window.rewardToken = IERC20(rewardToken);\\n window.ipfsHash = ipfsHash;\\n\\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\\n\\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\\n }\\n\\n // Verify claim is valid and mark it as completed in this contract.\\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\\n // Check claimed proof against merkle window at given index.\\n require(verifyClaim(_claim), \\\"Incorrect merkle proof\\\");\\n // Check the account has not yet claimed for this window.\\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \\\"Account has already claimed for this window\\\");\\n\\n // Proof is correct and claim has not occurred yet, mark claimed complete.\\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\\n emit Claimed(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x45ba14976c04b585ff82098ef0340ae062d9da7a3a2076b2535dbd194d254fc7\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\\n */\\ninterface MerkleDistributorInterface {\\n // A Window maps a Merkle root to a reward token address.\\n struct Window {\\n // Merkle root describing the distribution.\\n bytes32 merkleRoot;\\n // Remaining amount of deposited rewards that have not yet been claimed.\\n uint256 remainingAmount;\\n // Currency in which reward is processed.\\n IERC20 rewardToken;\\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\\n // data type for storing an IPFS hash is a multihash which is the concatenation of \\n // . We opted to store this in a string type to make it easier\\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\\n // go to https://cloudflare-ipfs.com/ipfs/.\\n string ipfsHash;\\n }\\n\\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\\n struct Claim {\\n uint256 windowIndex;\\n uint256 amount;\\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\\n address account;\\n bytes32[] merkleProof;\\n }\\n\\n function claim(Claim memory _claim) external;\\n\\n function claimMulti(Claim[] memory claims) external;\\n\\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\\n}\\n\",\"keccak256\":\"0x0d6527f44b268c3801d45bc1fc6021f22a80070a21d4066430a4d6566e3ff5e7\",\"license\":\"GPL-3.0-only\"},\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title Extended MerkleDistributor contract.\\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\\n */\\ncontract AcrossMerkleDistributor is MerkleDistributor {\\n using SafeERC20 for IERC20;\\n\\n // Addresses that can claim on user's behalf.\\n mapping(address => bool) public whitelistedClaimers;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\\n event ClaimFor(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Updates whitelisted claimer status.\\n * @dev Callable only by owner.\\n * @param newContract Reset claimer contract to this address.\\n * @param whitelist True to whitelist claimer, False otherwise.\\n */\\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\\n whitelistedClaimers[newContract] = whitelist;\\n emit WhitelistedClaimer(newContract, whitelist);\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev All claim recipients must be equal to msg.sender.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public override {\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n require(claims[i].account == msg.sender, \\\"invalid claimer\\\");\\n }\\n super.claimMulti(claims);\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev Claim recipient must be equal to msg.sender.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public override {\\n require(_claim.account == msg.sender, \\\"invalid claimer\\\");\\n super.claim(_claim);\\n }\\n\\n /**\\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\\n * claimer address. This function is designed to be called atomically with other transactions\\n * that ultimately return the claimed amount to the rightful recipient. For example,\\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\\n * @dev Caller must be in whitelistedClaimers struct set to \\\"true\\\".\\n * @param _claim leaf to claim.\\n */\\n\\n function claimFor(Claim memory _claim) public {\\n require(whitelistedClaimers[msg.sender], \\\"unwhitelisted claimer\\\");\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\\n emit ClaimFor(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x770e7f0986351870b1223a1214aaa3084b7cba9f438d7906c62c016ebd11b2c3\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611c3c8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063d6ef7af011610066578063d6ef7af01461026b578063e2e441a31461027e578063f2fde38b14610295578063f364c90c146102a857600080fd5b80638da5cb5b146102145780639f5a967214610232578063a198496c14610245578063d45118681461025857600080fd5b8063743817a0116100d3578063743817a01461016d578063761b42971461018057806388f038a2146101de578063891b0d71146101f157600080fd5b80634f512151146101055780636be651791461012d57806370b53aee14610142578063715018a614610165575b600080fd5b610118610113366004611749565b6102bb565b60405190151581526020015b60405180910390f35b61014061013b36600461177e565b610377565b005b61011861015036600461182f565b60046020526000908152604090205460ff1681565b61014061045b565b61014061017b36600461185a565b61046f565b6101b961018e366004611893565b60009081526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101406101ec366004611749565b6104f6565b6102046101ff366004611893565b61063e565b6040516101249493929190611922565b60005473ffffffffffffffffffffffffffffffffffffffff166101b9565b610140610240366004611893565b610707565b610140610253366004611749565b61079a565b610140610266366004611967565b610829565b6101406102793660046119fd565b610890565b61028760025481565b604051908152602001610124565b6101406102a336600461182f565b61090a565b6101186102b6366004611a29565b6109be565b6000808260600151836020015184604001516040516020016103179392919060609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001683526014830191909152603482015260540190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120608086015186516000908152600190945291909220549192506103709183610a09565b9392505050565b805160005b8181101561044d573373ffffffffffffffffffffffffffffffffffffffff168382815181106103ad576103ad611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161461043b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d6572000000000000000000000000000000000060448201526064015b60405180910390fd5b8061044581611aa9565b91505061037c565b5061045782610a1f565b5050565b610463610bb3565b61046d6000610c34565b565b610477610bb3565b73ffffffffffffffffffffffffffffffffffffffff821660008181526004602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917fbaa2323ab54d3ecd5bd63d3c3cfc23d7ef896edcbc927b7b7867407f32a3ba2991a35050565b3360009081526004602052604090205460ff1661056f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f756e77686974656c697374656420636c61696d657200000000000000000000006044820152606401610432565b61057881610ca9565b6020808201518251600090815260019092526040909120600201546105b79173ffffffffffffffffffffffffffffffffffffffff909116903390610e7c565b805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917fcfb930b6b49765485460cb1c6853ec3437a78b18d8c9a25b9fed2eea3b6756a991015b60405180910390a450565b60016020819052600091825260409091208054918101546002820154600383018054929373ffffffffffffffffffffffffffffffffffffffff9092169261068490611ae1565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090611ae1565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905084565b61070f610bb3565b600081815260016020819052604082208281559081018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559061076060038301826114b7565b505060405133815281907f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d669060200160405180910390a250565b606081015173ffffffffffffffffffffffffffffffffffffffff16331461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d657200000000000000000000000000000000006044820152606401610432565b61082681610f55565b50565b610831610bb3565b60025461083f816001611b34565b6002819055506108888187878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fa092505050565b505050505050565b610898610bb3565b6108b973ffffffffffffffffffffffffffffffffffffffff83163383610e7c565b60405181815273ffffffffffffffffffffffffffffffffffffffff83169033907ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e9060200160405180910390a35050565b610912610bb3565b73ffffffffffffffffffffffffffffffffffffffff81166109b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610432565b61082681610c34565b6000806109cd61010084611b7b565b905060006109dd61010085611b8f565b60009586526003602090815260408088209488529390529190942054600190911b908116149392505050565b600082610a16858461108b565b14949350505050565b8051600090815b81811015610bad576000848281518110610a4257610a42611a4b565b60200260200101519050610a5581610ca9565b6020810151610a649085611b34565b93506000610a73836001611b34565b825160009081526001602052604090206002015490915073ffffffffffffffffffffffffffffffffffffffff1684821480610afb5750826060015173ffffffffffffffffffffffffffffffffffffffff16878381518110610ad657610ad6611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1614155b80610b6657508073ffffffffffffffffffffffffffffffffffffffff1660016000898581518110610b2e57610b2e611a4b565b6020908102919091018101515182528101919091526040016000206002015473ffffffffffffffffffffffffffffffffffffffff1614155b15610b97576060830151610b929073ffffffffffffffffffffffffffffffffffffffff83169088610e7c565b600095505b5050508080610ba590611aa9565b915050610a26565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610432565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cb2816102bb565b610d18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e636f7272656374206d65726b6c652070726f6f66000000000000000000006044820152606401610432565b610d2a816000015182604001516109be565b15610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060448201527f746869732077696e646f770000000000000000000000000000000000000000006064820152608401610432565b610dc9816000015182604001516110d8565b806020015160016000836000015181526020019081526020016000206001016000828254610df79190611ba3565b9091555050805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b49101610633565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610f509084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611121565b505050565b610f5e81610ca9565b60608101516020808301518351600090815260019092526040909120600201546108269273ffffffffffffffffffffffffffffffffffffffff90911691610e7c565b60008581526001602081815260409092208481559081018690556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055825190916110119160038401918501906114f1565b506040805186815233602082015273ffffffffffffffffffffffffffffffffffffffff86169188917f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad910160405180910390a360028101546108889073ffffffffffffffffffffffffffffffffffffffff1633308861122d565b600081815b84518110156110d0576110bc828683815181106110af576110af611a4b565b602002602001015161128b565b9150806110c881611aa9565b915050611090565b509392505050565b60006110e661010083611b7b565b905060006110f661010084611b8f565b6000948552600360209081526040808720948752939052919093208054600190921b90911790555050565b6000611183826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112b79092919063ffffffff16565b805190915015610f5057808060200190518101906111a19190611bba565b610f50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610432565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610bad9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610ece565b60008183106112a7576000828152602084905260409020610370565b5060009182526020526040902090565b60606112c684846000856112ce565b949350505050565b606082471015611360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610432565b73ffffffffffffffffffffffffffffffffffffffff85163b6113de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610432565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516114079190611bd7565b60006040518083038185875af1925050503d8060008114611444576040519150601f19603f3d011682016040523d82523d6000602084013e611449565b606091505b5091509150611459828286611464565b979650505050505050565b60608315611473575081610370565b8251156114835782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104329190611bf3565b5080546114c390611ae1565b6000825580601f106114d3575050565b601f0160209004906000526020600020908101906108269190611575565b8280546114fd90611ae1565b90600052602060002090601f01602090048101928261151f5760008555611565565b82601f1061153857805160ff1916838001178555611565565b82800160010185558215611565579182015b8281111561156557825182559160200191906001019061154a565b50611571929150611575565b5090565b5b808211156115715760008155600101611576565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115dc576115dc61158a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156116295761162961158a565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461082657600080fd5b600067ffffffffffffffff82111561166d5761166d61158a565b5060051b60200190565b600060a0828403121561168957600080fd5b6116916115b9565b905081358152602080830135818301526040830135604083015260608301356116b981611631565b6060830152608083013567ffffffffffffffff8111156116d857600080fd5b8301601f810185136116e957600080fd5b80356116fc6116f782611653565b6115e2565b81815260059190911b8201830190838101908783111561171b57600080fd5b928401925b8284101561173957833582529284019290840190611720565b6080860152509295945050505050565b60006020828403121561175b57600080fd5b813567ffffffffffffffff81111561177257600080fd5b6112c684828501611677565b6000602080838503121561179157600080fd5b823567ffffffffffffffff808211156117a957600080fd5b818501915085601f8301126117bd57600080fd5b81356117cb6116f782611653565b81815260059190911b830184019084810190888311156117ea57600080fd5b8585015b83811015611822578035858111156118065760008081fd5b6118148b89838a0101611677565b8452509186019186016117ee565b5098975050505050505050565b60006020828403121561184157600080fd5b813561037081611631565b801515811461082657600080fd5b6000806040838503121561186d57600080fd5b823561187881611631565b915060208301356118888161184c565b809150509250929050565b6000602082840312156118a557600080fd5b5035919050565b60005b838110156118c75781810151838201526020016118af565b83811115610bad5750506000910152565b600081518084526118f08160208601602086016118ac565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b84815283602082015273ffffffffffffffffffffffffffffffffffffffff8316604082015260806060820152600061195d60808301846118d8565b9695505050505050565b60008060008060006080868803121561197f57600080fd5b85359450602086013561199181611631565b935060408601359250606086013567ffffffffffffffff808211156119b557600080fd5b818801915088601f8301126119c957600080fd5b8135818111156119d857600080fd5b8960208285010111156119ea57600080fd5b9699959850939650602001949392505050565b60008060408385031215611a1057600080fd5b8235611a1b81611631565b946020939093013593505050565b60008060408385031215611a3c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ada57611ada611a7a565b5060010190565b600181811c90821680611af557607f821691505b602082108103611b2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008219821115611b4757611b47611a7a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611b8a57611b8a611b4c565b500490565b600082611b9e57611b9e611b4c565b500690565b600082821015611bb557611bb5611a7a565b500390565b600060208284031215611bcc57600080fd5b81516103708161184c565b60008251611be98184602087016118ac565b9190910192915050565b60208152600061037060208301846118d856fea26469706673582212204e7d4cbb315ebe595a6cc88f23a8e65a5517a72a4d9d103a40e984d8af7af15664736f6c634300080d0033", "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063d6ef7af011610066578063d6ef7af01461026b578063e2e441a31461027e578063f2fde38b14610295578063f364c90c146102a857600080fd5b80638da5cb5b146102145780639f5a967214610232578063a198496c14610245578063d45118681461025857600080fd5b8063743817a0116100d3578063743817a01461016d578063761b42971461018057806388f038a2146101de578063891b0d71146101f157600080fd5b80634f512151146101055780636be651791461012d57806370b53aee14610142578063715018a614610165575b600080fd5b610118610113366004611749565b6102bb565b60405190151581526020015b60405180910390f35b61014061013b36600461177e565b610377565b005b61011861015036600461182f565b60046020526000908152604090205460ff1681565b61014061045b565b61014061017b36600461185a565b61046f565b6101b961018e366004611893565b60009081526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101406101ec366004611749565b6104f6565b6102046101ff366004611893565b61063e565b6040516101249493929190611922565b60005473ffffffffffffffffffffffffffffffffffffffff166101b9565b610140610240366004611893565b610707565b610140610253366004611749565b61079a565b610140610266366004611967565b610829565b6101406102793660046119fd565b610890565b61028760025481565b604051908152602001610124565b6101406102a336600461182f565b61090a565b6101186102b6366004611a29565b6109be565b6000808260600151836020015184604001516040516020016103179392919060609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001683526014830191909152603482015260540190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120608086015186516000908152600190945291909220549192506103709183610a09565b9392505050565b805160005b8181101561044d573373ffffffffffffffffffffffffffffffffffffffff168382815181106103ad576103ad611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161461043b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d6572000000000000000000000000000000000060448201526064015b60405180910390fd5b8061044581611aa9565b91505061037c565b5061045782610a1f565b5050565b610463610bb3565b61046d6000610c34565b565b610477610bb3565b73ffffffffffffffffffffffffffffffffffffffff821660008181526004602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917fbaa2323ab54d3ecd5bd63d3c3cfc23d7ef896edcbc927b7b7867407f32a3ba2991a35050565b3360009081526004602052604090205460ff1661056f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f756e77686974656c697374656420636c61696d657200000000000000000000006044820152606401610432565b61057881610ca9565b6020808201518251600090815260019092526040909120600201546105b79173ffffffffffffffffffffffffffffffffffffffff909116903390610e7c565b805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917fcfb930b6b49765485460cb1c6853ec3437a78b18d8c9a25b9fed2eea3b6756a991015b60405180910390a450565b60016020819052600091825260409091208054918101546002820154600383018054929373ffffffffffffffffffffffffffffffffffffffff9092169261068490611ae1565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090611ae1565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905084565b61070f610bb3565b600081815260016020819052604082208281559081018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559061076060038301826114b7565b505060405133815281907f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d669060200160405180910390a250565b606081015173ffffffffffffffffffffffffffffffffffffffff16331461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d657200000000000000000000000000000000006044820152606401610432565b61082681610f55565b50565b610831610bb3565b60025461083f816001611b34565b6002819055506108888187878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fa092505050565b505050505050565b610898610bb3565b6108b973ffffffffffffffffffffffffffffffffffffffff83163383610e7c565b60405181815273ffffffffffffffffffffffffffffffffffffffff83169033907ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e9060200160405180910390a35050565b610912610bb3565b73ffffffffffffffffffffffffffffffffffffffff81166109b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610432565b61082681610c34565b6000806109cd61010084611b7b565b905060006109dd61010085611b8f565b60009586526003602090815260408088209488529390529190942054600190911b908116149392505050565b600082610a16858461108b565b14949350505050565b8051600090815b81811015610bad576000848281518110610a4257610a42611a4b565b60200260200101519050610a5581610ca9565b6020810151610a649085611b34565b93506000610a73836001611b34565b825160009081526001602052604090206002015490915073ffffffffffffffffffffffffffffffffffffffff1684821480610afb5750826060015173ffffffffffffffffffffffffffffffffffffffff16878381518110610ad657610ad6611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1614155b80610b6657508073ffffffffffffffffffffffffffffffffffffffff1660016000898581518110610b2e57610b2e611a4b565b6020908102919091018101515182528101919091526040016000206002015473ffffffffffffffffffffffffffffffffffffffff1614155b15610b97576060830151610b929073ffffffffffffffffffffffffffffffffffffffff83169088610e7c565b600095505b5050508080610ba590611aa9565b915050610a26565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610432565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cb2816102bb565b610d18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e636f7272656374206d65726b6c652070726f6f66000000000000000000006044820152606401610432565b610d2a816000015182604001516109be565b15610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060448201527f746869732077696e646f770000000000000000000000000000000000000000006064820152608401610432565b610dc9816000015182604001516110d8565b806020015160016000836000015181526020019081526020016000206001016000828254610df79190611ba3565b9091555050805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b49101610633565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610f509084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611121565b505050565b610f5e81610ca9565b60608101516020808301518351600090815260019092526040909120600201546108269273ffffffffffffffffffffffffffffffffffffffff90911691610e7c565b60008581526001602081815260409092208481559081018690556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055825190916110119160038401918501906114f1565b506040805186815233602082015273ffffffffffffffffffffffffffffffffffffffff86169188917f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad910160405180910390a360028101546108889073ffffffffffffffffffffffffffffffffffffffff1633308861122d565b600081815b84518110156110d0576110bc828683815181106110af576110af611a4b565b602002602001015161128b565b9150806110c881611aa9565b915050611090565b509392505050565b60006110e661010083611b7b565b905060006110f661010084611b8f565b6000948552600360209081526040808720948752939052919093208054600190921b90911790555050565b6000611183826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112b79092919063ffffffff16565b805190915015610f5057808060200190518101906111a19190611bba565b610f50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610432565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610bad9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610ece565b60008183106112a7576000828152602084905260409020610370565b5060009182526020526040902090565b60606112c684846000856112ce565b949350505050565b606082471015611360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610432565b73ffffffffffffffffffffffffffffffffffffffff85163b6113de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610432565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516114079190611bd7565b60006040518083038185875af1925050503d8060008114611444576040519150601f19603f3d011682016040523d82523d6000602084013e611449565b606091505b5091509150611459828286611464565b979650505050505050565b60608315611473575081610370565b8251156114835782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104329190611bf3565b5080546114c390611ae1565b6000825580601f106114d3575050565b601f0160209004906000526020600020908101906108269190611575565b8280546114fd90611ae1565b90600052602060002090601f01602090048101928261151f5760008555611565565b82601f1061153857805160ff1916838001178555611565565b82800160010185558215611565579182015b8281111561156557825182559160200191906001019061154a565b50611571929150611575565b5090565b5b808211156115715760008155600101611576565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115dc576115dc61158a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156116295761162961158a565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461082657600080fd5b600067ffffffffffffffff82111561166d5761166d61158a565b5060051b60200190565b600060a0828403121561168957600080fd5b6116916115b9565b905081358152602080830135818301526040830135604083015260608301356116b981611631565b6060830152608083013567ffffffffffffffff8111156116d857600080fd5b8301601f810185136116e957600080fd5b80356116fc6116f782611653565b6115e2565b81815260059190911b8201830190838101908783111561171b57600080fd5b928401925b8284101561173957833582529284019290840190611720565b6080860152509295945050505050565b60006020828403121561175b57600080fd5b813567ffffffffffffffff81111561177257600080fd5b6112c684828501611677565b6000602080838503121561179157600080fd5b823567ffffffffffffffff808211156117a957600080fd5b818501915085601f8301126117bd57600080fd5b81356117cb6116f782611653565b81815260059190911b830184019084810190888311156117ea57600080fd5b8585015b83811015611822578035858111156118065760008081fd5b6118148b89838a0101611677565b8452509186019186016117ee565b5098975050505050505050565b60006020828403121561184157600080fd5b813561037081611631565b801515811461082657600080fd5b6000806040838503121561186d57600080fd5b823561187881611631565b915060208301356118888161184c565b809150509250929050565b6000602082840312156118a557600080fd5b5035919050565b60005b838110156118c75781810151838201526020016118af565b83811115610bad5750506000910152565b600081518084526118f08160208601602086016118ac565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b84815283602082015273ffffffffffffffffffffffffffffffffffffffff8316604082015260806060820152600061195d60808301846118d8565b9695505050505050565b60008060008060006080868803121561197f57600080fd5b85359450602086013561199181611631565b935060408601359250606086013567ffffffffffffffff808211156119b557600080fd5b818801915088601f8301126119c957600080fd5b8135818111156119d857600080fd5b8960208285010111156119ea57600080fd5b9699959850939650602001949392505050565b60008060408385031215611a1057600080fd5b8235611a1b81611631565b946020939093013593505050565b60008060408385031215611a3c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ada57611ada611a7a565b5060010190565b600181811c90821680611af557607f821691505b602082108103611b2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008219821115611b4757611b47611a7a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611b8a57611b8a611b4c565b500490565b600082611b9e57611b9e611b4c565b500690565b600082821015611bb557611bb5611a7a565b500390565b600060208284031215611bcc57600080fd5b81516103708161184c565b60008251611be98184602087016118ac565b9190910192915050565b60208152600061037060208301846118d856fea26469706673582212204e7d4cbb315ebe595a6cc88f23a8e65a5517a72a4d9d103a40e984d8af7af15664736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Arbitrum_Adapter.json b/deployments/goerli/Arbitrum_Adapter.json index 1d7ddc15..8db11bd4 100644 --- a/deployments/goerli/Arbitrum_Adapter.json +++ b/deployments/goerli/Arbitrum_Adapter.json @@ -224,7 +224,7 @@ "args": ["0x6BEbC4925716945D46F0Ec336D5C2564F419682C", "0x4c7708168395aEa569453Fc36862D2ffcDaC588c"], "numDeployments": 1, "solcInputHash": "2703c51b0457010edb5371429c04306b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2 and lost.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x26bf6695b4dc412fbacc090aae47284bfc6eb4cfc357dea4843fa74ccb96885d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2 and lost.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x26bf6695b4dc412fbacc090aae47284bfc6eb4cfc357dea4843fa74ccb96885d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052662386f26fc1000060805264012a05f20060a052621e848060c05234801561002c57600080fd5b5060405161128438038061128483398101604081905261004b91610080565b6001600160a01b039182166101005216610120523360e0526100ba565b6001600160a01b038116811461007d57600080fd5b50565b6000806040838503121561009357600080fd5b825161009e81610068565b60208401519092506100af81610068565b809150509250929050565b60805160a05160c05160e051610100516101205161111a61016a6000396000818160d501528181610333015261047001526000818161014301526105cd0152600081816101ab0152818161062e015261064f0152600081816101df01528181610269015281816104a501526106700152600081816101770152818161028b015281816104c70152610691015260008181610228015281816102b5015281816103c5015261060d015261111a6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212203e211fa11542a3146dbf1d5afde804b46ca1cc0ca35ecbd1eccc4f553457584d64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212203e211fa11542a3146dbf1d5afde804b46ca1cc0ca35ecbd1eccc4f553457584d64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Ethereum_Adapter.json b/deployments/goerli/Ethereum_Adapter.json index ceae3dc9..9cbf6131 100644 --- a/deployments/goerli/Ethereum_Adapter.json +++ b/deployments/goerli/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "6f2837d4a3b71ee9ce7179486eec7c62", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n\\n bool success;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xcfef0f4e9715e55426bcb08f18a04d437358f381b456a2af7262ead48c6987cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n\\n bool success;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xcfef0f4e9715e55426bcb08f18a04d437358f381b456a2af7262ead48c6987cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220e95c79b0243d04b77fff68509adf0775fd47ea5ad3499e9e6141c4fdb0b5d6cc64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220e95c79b0243d04b77fff68509adf0775fd47ea5ad3499e9e6141c4fdb0b5d6cc64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Ethereum_SpokePool.json b/deployments/goerli/Ethereum_SpokePool.json index 222fb8ec..18adc445 100644 --- a/deployments/goerli/Ethereum_SpokePool.json +++ b/deployments/goerli/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "6f2837d4a3b71ee9ce7179486eec7c62", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x84ac2d2f343df1e683da7a12bbcf70db542a7a7a0cea90a5d70fcb5e5d035481\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x84ac2d2f343df1e683da7a12bbcf70db542a7a7a0cea90a5d70fcb5e5d035481\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004589380380620045898339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b6080516142a0620002e9600039600081816101d901528181610ce601528181610daf0152818161226301528181612ae90152612b3f01526142a06000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461358b565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613687565b6106b0565b3480156102a057600080fd5b506102456102af3660046136a2565b61073d565b3480156102c057600080fd5b506102456102cf3660046136c9565b6107e6565b3480156102e057600080fd5b506102456102ef366004613709565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461373c565b610ab1565b34801561033657600080fd5b506102456103453660046137a2565b610f28565b34801561035657600080fd5b506103856103653660046137c4565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046137ee565b611056565b34801561044d57600080fd5b5061024561045c3660046136a2565b6111b2565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461388c565b611286565b60405161021c9190613977565b34801561050457600080fd5b506102456105133660046139f7565b611460565b34801561052457600080fd5b50610245610533366004613687565b6114ec565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613b55565b611532565b34801561059157600080fd5b506105a56105a03660046136a2565b611690565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d53660046136a2565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613687565b6116be565b34801561061357600080fd5b50610245610622366004613bc4565b611772565b61062f6118dd565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611961565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611d0d565b6106c06118dd565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611d15565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611d0d565b6107f66118dd565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611d0d565b6109086118dd565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613ca2565b905090565b504290565b610ab96118dd565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613cea565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613d0f565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611e01565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611edd565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613d37565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611d0d565b610f386118dd565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61104a611f6e565b6110546000611fef565b565b61105e6118dd565b61108b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111004690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061113c82612066565b9050600061114e82848b886000612096565b905061115f82828a88876000612343565b5050506111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6111ba611d0d565b6111c26118dd565b6111ef600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061120257611202613d5a565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156112f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611309576113096133cf565b60405190808252806020026020018201604052801561133c57816020015b60608152602001906001900390816113275790505b50905060005b82811015611459576000803086868581811061136057611360613d5a565b90506020028101906113729190613d89565b604051611380929190613dee565b600060405180830381855af49150503d80600081146113bb576040519150601f19603f3d011682016040523d82523d6000602084013e6113c0565b606091505b509150915081611426576044815110156113d957600080fd5b600481019050808060200190518101906113f39190613dfe565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b8084848151811061143957611439613d5a565b60200260200101819052505050808061145190613e7f565b915050611342565b5092915050565b6114686118dd565b611495600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6114a88a8a8a8a8a468b8b8b8b8b612485565b6111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6114f4611d0d565b6114fc6118dd565b611529600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681612604565b61153a6118dd565b611567600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106115e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b6115ef84468585856126f0565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d37858460405161163e929190613eb7565b60405180910390a361168a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106116a057600080fd5b60009182526020909120600390910201805460019091015490915082565b6116c6611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611769576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a81611fef565b61177a6118dd565b6117a7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6117b48c878585856126f0565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020018881526020016118294690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061186582612066565b9050600061187782848d896000612096565b905061188882828c89876000612343565b5050506118cf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff16611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b468260200151146119ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611a5c57611a5c613d5a565b90600052602060002090600302019050611a7b8160010154848461278d565b611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611af881600201846060015163ffffffff166127ca565b15611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611b7681600201846060015163ffffffff1661280b565b60408301515160005b81811015611c0757600085604001518281518110611b9f57611b9f613d5a565b602002602001015190506000811115611bfe57611bfe8660a001518381518110611bcb57611bcb613d5a565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50600101611b7f565b50835115611ca057611c188461289f565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611c9792919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611cfe959493929190613f5b565b60405180910390a45050505050565b611054611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261168a9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612943565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000816040516020016120799190613fb9565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156120ce57506706f05b59d3b200008560c0015167ffffffffffffffff16105b612134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106121af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036121bf5750600061233a565b6121d884848760c001516121d39190614060565b612a4f565b600087815260056020526040812054606088015192935086926121fb9190614083565b9050828110156122245780925061222183868960c0015161221c9190614060565b612a89565b91505b6000888152600560205260408120805485929061224290849061409a565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036122ca57836122b75760408701516122b79073ffffffffffffffffffffffffffffffffffffffff16333085611e01565b6122c5876020015183612ab2565b612337565b83612304576122c5338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611e01909392919063ffffffff16565b612337876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516124759d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061255a60038463ffffffff168154811061254157612541613d5a565b9060005260206000209060030201600001548284612bf3565b6125c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006125cb82612066565b905060006125e28284856060015160006001612096565b90506125f48282600080876001612343565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612681576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061277782612c0b565b9050612784878285612c46565b50505050505050565b60006127c08285856040516020016127a591906140b2565b60405160208183030381529060405280519060200120612ce4565b90505b9392505050565b6000806127d96101008461417c565b905060006127e961010085614190565b6000928352602095909552506040902054600190931b92831690921492915050565b60006128196101008361417c565b9050600061282961010084614190565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611e5b565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af115801561291f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e91906141a4565b60006129a5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612cfa9092919063ffffffff16565b8051909150156106ab57808060200190518101906129c391906141a4565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612a6382670de0b6b3a76400006141c1565b67ffffffffffffffff16612a7f84670de0b6b3a76400006141e2565b6127c3919061417c565b6000670de0b6b3a7640000612a9e83826141c1565b612a7f9067ffffffffffffffff16856141e2565b73ffffffffffffffffffffffffffffffffffffffff82163b15612b105761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612849565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b9857600080fd5b505af1158015612bac573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006127c08285856040516020016127a59190613fb9565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612079565b612c508282612d09565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612cf18584612d2d565b14949350505050565b60606127c08484600085612d72565b6000806000612d188585612f08565b91509150612d2581612f76565b509392505050565b600081815b8451811015612d2557612d5e82868381518110612d5157612d51613d5a565b60200260200101516131ca565b915080612d6a81613e7f565b915050612d32565b606082471015612e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612e82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612eab919061421f565b60006040518083038185875af1925050503d8060008114612ee8576040519150601f19603f3d011682016040523d82523d6000602084013e612eed565b606091505b5091509150612efd8282866131f9565b979650505050505050565b6000808251604103612f3e5760208301516040840151606085015160001a612f328782858561324c565b94509450505050612f6f565b8251604003612f675760208301516040840151612f5c868383613364565b935093505050612f6f565b506000905060025b9250929050565b6000816004811115612f8a57612f8a61423b565b03612f925750565b6001816004811115612fa657612fa661423b565b0361300d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156130215761302161423b565b03613088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b600381600481111561309c5761309c61423b565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561313d5761313d61423b565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b60008183106131e65760008281526020849052604090206127c3565b60008381526020839052604090206127c3565b606083156132085750816127c3565b8251156132185782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613283575060009050600361335b565b8460ff16601b1415801561329b57508460ff16601c14155b156132ac575060009050600461335b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613300573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133545760006001925092505061335b565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161339a60ff86901c601b61409a565b90506133a88782888561324c565b935093505050935093915050565b803563ffffffff811681146133ca57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613421576134216133cf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561346e5761346e6133cf565b604052919050565b600067ffffffffffffffff821115613490576134906133cf565b5060051b60200190565b600082601f8301126134ab57600080fd5b813560206134c06134bb83613476565b613427565b82815260059290921b840181019181810190868411156134df57600080fd5b8286015b848110156134fa57803583529183019183016134e3565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146133ca57600080fd5b600082601f83011261353a57600080fd5b8135602061354a6134bb83613476565b82815260059290921b8401810191818101908684111561356957600080fd5b8286015b848110156134fa5761357e81613505565b835291830191830161356d565b6000806000606084860312156135a057600080fd5b6135a9846133b6565b9250602084013567ffffffffffffffff808211156135c657600080fd5b9085019060c082880312156135da57600080fd5b6135e26133fe565b823581526020830135602082015260408301358281111561360257600080fd5b61360e8982860161349a565b604083015250613620606084016133b6565b606082015261363160808401613505565b608082015260a08301358281111561364857600080fd5b61365489828601613529565b60a0830152509350604086013591508082111561367057600080fd5b5061367d8682870161349a565b9150509250925092565b60006020828403121561369957600080fd5b6127c382613505565b6000602082840312156136b457600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156136de57600080fd5b6136e784613505565b92506020840135915060408401356136fe816136bb565b809150509250925092565b60006020828403121561371b57600080fd5b6127c3826133b6565b803567ffffffffffffffff811681146133ca57600080fd5b60008060008060008060c0878903121561375557600080fd5b61375e87613505565b955061376c60208801613505565b9450604087013593506060870135925061378860808801613724565b915061379660a088016133b6565b90509295509295509295565b600080604083850312156137b557600080fd5b50508035926020909101359150565b600080604083850312156137d757600080fd5b6137e083613505565b946020939093013593505050565b6000806000806000806000806000806101408b8d03121561380e57600080fd5b6138178b613505565b995061382560208c01613505565b985061383360408c01613505565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061385d60e08c01613724565b925061386c6101008c01613724565b915061387b6101208c016133b6565b90509295989b9194979a5092959850565b6000806020838503121561389f57600080fd5b823567ffffffffffffffff808211156138b757600080fd5b818501915085601f8301126138cb57600080fd5b8135818111156138da57600080fd5b8660208260051b85010111156138ef57600080fd5b60209290920196919550909350505050565b60005b8381101561391c578181015183820152602001613904565b8381111561168a5750506000910152565b60008151808452613945816020860160208601613901565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139ea577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139d885835161392d565b9450928501929085019060010161399e565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613a1757600080fd5b613a208b613505565b9950613a2e60208c01613505565b9850613a3c60408c01613505565b975060608b0135965060808b01359550613a5860a08c01613724565b9450613a6660c08c01613724565b9350613a7460e08c016133b6565b9250613a836101008c016133b6565b91506101208b013567ffffffffffffffff811115613aa057600080fd5b613aac8d828e0161349a565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613ad857613ad86133cf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613b1557600080fd5b8135613b236134bb82613abe565b818152846020838601011115613b3857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613b6b57600080fd5b613b7485613505565b9350613b8260208601613724565b9250613b90604086016133b6565b9150606085013567ffffffffffffffff811115613bac57600080fd5b613bb887828801613b04565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613be757600080fd5b613bf08d613505565b9b50613bfe60208e01613505565b9a50613c0c60408e01613505565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613c3660e08e01613724565b9450613c456101008e01613724565b9350613c546101208e01613724565b9250613c636101408e016133b6565b915067ffffffffffffffff6101608e01351115613c7f57600080fd5b613c908e6101608f01358f01613b04565b90509295989b509295989b509295989b565b600060208284031215613cb457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613d0757613d07613cbb565b039392505050565b600063ffffffff808316818516808303821115613d2e57613d2e613cbb565b01949350505050565b600063ffffffff808316818103613d5057613d50613cbb565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613dbe57600080fd5b83018035915067ffffffffffffffff821115613dd957600080fd5b602001915036819003821315612f6f57600080fd5b8183823760009101908152919050565b600060208284031215613e1057600080fd5b815167ffffffffffffffff811115613e2757600080fd5b8201601f81018413613e3857600080fd5b8051613e466134bb82613abe565b818152856020838501011115613e5b57600080fd5b61233a826020830160208601613901565b6020815260006127c3602083018461392d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613eb057613eb0613cbb565b5060010190565b67ffffffffffffffff831681526040602082015260006127c0604083018461392d565b600081518084526020808501945080840160005b83811015613f0a57815187529582019590820190600101613eee565b509495945050505050565b600081518084526020808501945080840160005b83811015613f0a57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f29565b85815260a060208201526000613f7460a0830187613eda565b73ffffffffffffffffffffffffffffffffffffffff80871660408501528382036060850152613fa38287613f15565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161402e60c084018267ffffffffffffffff169052565b5060e083015161404a60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613d2e57613d2e613cbb565b60008282101561409557614095613cbb565b500390565b600082198211156140ad576140ad613cbb565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526140e260e0840182613eda565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261233a8282613f15565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261418b5761418b61414d565b500490565b60008261419f5761419f61414d565b500690565b6000602082840312156141b657600080fd5b81516127c3816136bb565b600067ffffffffffffffff83811690831681811015613d0757613d07613cbb565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561421a5761421a613cbb565b500290565b60008251614231818460208701613901565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220a17e1594490c351dd225042fbaf4b4f5d0ac374b48a80a2fbd76ec203fa1d35464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461358b565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613687565b6106b0565b3480156102a057600080fd5b506102456102af3660046136a2565b61073d565b3480156102c057600080fd5b506102456102cf3660046136c9565b6107e6565b3480156102e057600080fd5b506102456102ef366004613709565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461373c565b610ab1565b34801561033657600080fd5b506102456103453660046137a2565b610f28565b34801561035657600080fd5b506103856103653660046137c4565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046137ee565b611056565b34801561044d57600080fd5b5061024561045c3660046136a2565b6111b2565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461388c565b611286565b60405161021c9190613977565b34801561050457600080fd5b506102456105133660046139f7565b611460565b34801561052457600080fd5b50610245610533366004613687565b6114ec565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613b55565b611532565b34801561059157600080fd5b506105a56105a03660046136a2565b611690565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d53660046136a2565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613687565b6116be565b34801561061357600080fd5b50610245610622366004613bc4565b611772565b61062f6118dd565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611961565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611d0d565b6106c06118dd565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611d15565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611d0d565b6107f66118dd565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611d0d565b6109086118dd565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613ca2565b905090565b504290565b610ab96118dd565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613cea565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613d0f565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611e01565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611edd565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613d37565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611d0d565b610f386118dd565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61104a611f6e565b6110546000611fef565b565b61105e6118dd565b61108b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111004690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061113c82612066565b9050600061114e82848b886000612096565b905061115f82828a88876000612343565b5050506111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6111ba611d0d565b6111c26118dd565b6111ef600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061120257611202613d5a565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156112f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611309576113096133cf565b60405190808252806020026020018201604052801561133c57816020015b60608152602001906001900390816113275790505b50905060005b82811015611459576000803086868581811061136057611360613d5a565b90506020028101906113729190613d89565b604051611380929190613dee565b600060405180830381855af49150503d80600081146113bb576040519150601f19603f3d011682016040523d82523d6000602084013e6113c0565b606091505b509150915081611426576044815110156113d957600080fd5b600481019050808060200190518101906113f39190613dfe565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b8084848151811061143957611439613d5a565b60200260200101819052505050808061145190613e7f565b915050611342565b5092915050565b6114686118dd565b611495600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6114a88a8a8a8a8a468b8b8b8b8b612485565b6111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6114f4611d0d565b6114fc6118dd565b611529600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681612604565b61153a6118dd565b611567600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106115e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b6115ef84468585856126f0565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d37858460405161163e929190613eb7565b60405180910390a361168a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106116a057600080fd5b60009182526020909120600390910201805460019091015490915082565b6116c6611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611769576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a81611fef565b61177a6118dd565b6117a7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6117b48c878585856126f0565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020018881526020016118294690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061186582612066565b9050600061187782848d896000612096565b905061188882828c89876000612343565b5050506118cf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff16611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b468260200151146119ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611a5c57611a5c613d5a565b90600052602060002090600302019050611a7b8160010154848461278d565b611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611af881600201846060015163ffffffff166127ca565b15611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611b7681600201846060015163ffffffff1661280b565b60408301515160005b81811015611c0757600085604001518281518110611b9f57611b9f613d5a565b602002602001015190506000811115611bfe57611bfe8660a001518381518110611bcb57611bcb613d5a565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50600101611b7f565b50835115611ca057611c188461289f565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611c9792919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611cfe959493929190613f5b565b60405180910390a45050505050565b611054611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261168a9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612943565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000816040516020016120799190613fb9565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156120ce57506706f05b59d3b200008560c0015167ffffffffffffffff16105b612134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106121af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036121bf5750600061233a565b6121d884848760c001516121d39190614060565b612a4f565b600087815260056020526040812054606088015192935086926121fb9190614083565b9050828110156122245780925061222183868960c0015161221c9190614060565b612a89565b91505b6000888152600560205260408120805485929061224290849061409a565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036122ca57836122b75760408701516122b79073ffffffffffffffffffffffffffffffffffffffff16333085611e01565b6122c5876020015183612ab2565b612337565b83612304576122c5338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611e01909392919063ffffffff16565b612337876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516124759d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061255a60038463ffffffff168154811061254157612541613d5a565b9060005260206000209060030201600001548284612bf3565b6125c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006125cb82612066565b905060006125e28284856060015160006001612096565b90506125f48282600080876001612343565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612681576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061277782612c0b565b9050612784878285612c46565b50505050505050565b60006127c08285856040516020016127a591906140b2565b60405160208183030381529060405280519060200120612ce4565b90505b9392505050565b6000806127d96101008461417c565b905060006127e961010085614190565b6000928352602095909552506040902054600190931b92831690921492915050565b60006128196101008361417c565b9050600061282961010084614190565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611e5b565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af115801561291f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e91906141a4565b60006129a5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612cfa9092919063ffffffff16565b8051909150156106ab57808060200190518101906129c391906141a4565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612a6382670de0b6b3a76400006141c1565b67ffffffffffffffff16612a7f84670de0b6b3a76400006141e2565b6127c3919061417c565b6000670de0b6b3a7640000612a9e83826141c1565b612a7f9067ffffffffffffffff16856141e2565b73ffffffffffffffffffffffffffffffffffffffff82163b15612b105761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612849565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b9857600080fd5b505af1158015612bac573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006127c08285856040516020016127a59190613fb9565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612079565b612c508282612d09565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612cf18584612d2d565b14949350505050565b60606127c08484600085612d72565b6000806000612d188585612f08565b91509150612d2581612f76565b509392505050565b600081815b8451811015612d2557612d5e82868381518110612d5157612d51613d5a565b60200260200101516131ca565b915080612d6a81613e7f565b915050612d32565b606082471015612e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612e82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612eab919061421f565b60006040518083038185875af1925050503d8060008114612ee8576040519150601f19603f3d011682016040523d82523d6000602084013e612eed565b606091505b5091509150612efd8282866131f9565b979650505050505050565b6000808251604103612f3e5760208301516040840151606085015160001a612f328782858561324c565b94509450505050612f6f565b8251604003612f675760208301516040840151612f5c868383613364565b935093505050612f6f565b506000905060025b9250929050565b6000816004811115612f8a57612f8a61423b565b03612f925750565b6001816004811115612fa657612fa661423b565b0361300d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156130215761302161423b565b03613088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b600381600481111561309c5761309c61423b565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561313d5761313d61423b565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b60008183106131e65760008281526020849052604090206127c3565b60008381526020839052604090206127c3565b606083156132085750816127c3565b8251156132185782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613283575060009050600361335b565b8460ff16601b1415801561329b57508460ff16601c14155b156132ac575060009050600461335b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613300573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133545760006001925092505061335b565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161339a60ff86901c601b61409a565b90506133a88782888561324c565b935093505050935093915050565b803563ffffffff811681146133ca57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613421576134216133cf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561346e5761346e6133cf565b604052919050565b600067ffffffffffffffff821115613490576134906133cf565b5060051b60200190565b600082601f8301126134ab57600080fd5b813560206134c06134bb83613476565b613427565b82815260059290921b840181019181810190868411156134df57600080fd5b8286015b848110156134fa57803583529183019183016134e3565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146133ca57600080fd5b600082601f83011261353a57600080fd5b8135602061354a6134bb83613476565b82815260059290921b8401810191818101908684111561356957600080fd5b8286015b848110156134fa5761357e81613505565b835291830191830161356d565b6000806000606084860312156135a057600080fd5b6135a9846133b6565b9250602084013567ffffffffffffffff808211156135c657600080fd5b9085019060c082880312156135da57600080fd5b6135e26133fe565b823581526020830135602082015260408301358281111561360257600080fd5b61360e8982860161349a565b604083015250613620606084016133b6565b606082015261363160808401613505565b608082015260a08301358281111561364857600080fd5b61365489828601613529565b60a0830152509350604086013591508082111561367057600080fd5b5061367d8682870161349a565b9150509250925092565b60006020828403121561369957600080fd5b6127c382613505565b6000602082840312156136b457600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156136de57600080fd5b6136e784613505565b92506020840135915060408401356136fe816136bb565b809150509250925092565b60006020828403121561371b57600080fd5b6127c3826133b6565b803567ffffffffffffffff811681146133ca57600080fd5b60008060008060008060c0878903121561375557600080fd5b61375e87613505565b955061376c60208801613505565b9450604087013593506060870135925061378860808801613724565b915061379660a088016133b6565b90509295509295509295565b600080604083850312156137b557600080fd5b50508035926020909101359150565b600080604083850312156137d757600080fd5b6137e083613505565b946020939093013593505050565b6000806000806000806000806000806101408b8d03121561380e57600080fd5b6138178b613505565b995061382560208c01613505565b985061383360408c01613505565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061385d60e08c01613724565b925061386c6101008c01613724565b915061387b6101208c016133b6565b90509295989b9194979a5092959850565b6000806020838503121561389f57600080fd5b823567ffffffffffffffff808211156138b757600080fd5b818501915085601f8301126138cb57600080fd5b8135818111156138da57600080fd5b8660208260051b85010111156138ef57600080fd5b60209290920196919550909350505050565b60005b8381101561391c578181015183820152602001613904565b8381111561168a5750506000910152565b60008151808452613945816020860160208601613901565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139ea577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139d885835161392d565b9450928501929085019060010161399e565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613a1757600080fd5b613a208b613505565b9950613a2e60208c01613505565b9850613a3c60408c01613505565b975060608b0135965060808b01359550613a5860a08c01613724565b9450613a6660c08c01613724565b9350613a7460e08c016133b6565b9250613a836101008c016133b6565b91506101208b013567ffffffffffffffff811115613aa057600080fd5b613aac8d828e0161349a565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613ad857613ad86133cf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613b1557600080fd5b8135613b236134bb82613abe565b818152846020838601011115613b3857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613b6b57600080fd5b613b7485613505565b9350613b8260208601613724565b9250613b90604086016133b6565b9150606085013567ffffffffffffffff811115613bac57600080fd5b613bb887828801613b04565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613be757600080fd5b613bf08d613505565b9b50613bfe60208e01613505565b9a50613c0c60408e01613505565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613c3660e08e01613724565b9450613c456101008e01613724565b9350613c546101208e01613724565b9250613c636101408e016133b6565b915067ffffffffffffffff6101608e01351115613c7f57600080fd5b613c908e6101608f01358f01613b04565b90509295989b509295989b509295989b565b600060208284031215613cb457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613d0757613d07613cbb565b039392505050565b600063ffffffff808316818516808303821115613d2e57613d2e613cbb565b01949350505050565b600063ffffffff808316818103613d5057613d50613cbb565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613dbe57600080fd5b83018035915067ffffffffffffffff821115613dd957600080fd5b602001915036819003821315612f6f57600080fd5b8183823760009101908152919050565b600060208284031215613e1057600080fd5b815167ffffffffffffffff811115613e2757600080fd5b8201601f81018413613e3857600080fd5b8051613e466134bb82613abe565b818152856020838501011115613e5b57600080fd5b61233a826020830160208601613901565b6020815260006127c3602083018461392d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613eb057613eb0613cbb565b5060010190565b67ffffffffffffffff831681526040602082015260006127c0604083018461392d565b600081518084526020808501945080840160005b83811015613f0a57815187529582019590820190600101613eee565b509495945050505050565b600081518084526020808501945080840160005b83811015613f0a57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f29565b85815260a060208201526000613f7460a0830187613eda565b73ffffffffffffffffffffffffffffffffffffffff80871660408501528382036060850152613fa38287613f15565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161402e60c084018267ffffffffffffffff169052565b5060e083015161404a60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613d2e57613d2e613cbb565b60008282101561409557614095613cbb565b500390565b600082198211156140ad576140ad613cbb565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526140e260e0840182613eda565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261233a8282613f15565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261418b5761418b61414d565b500490565b60008261419f5761419f61414d565b500690565b6000602082840312156141b657600080fd5b81516127c3816136bb565b600067ffffffffffffffff83811690831681811015613d0757613d07613cbb565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561421a5761421a613cbb565b500290565b60008251614231818460208701613901565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220a17e1594490c351dd225042fbaf4b4f5d0ac374b48a80a2fbd76ec203fa1d35464736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/LpTokenFactory.json b/deployments/goerli/LpTokenFactory.json index 412a1a44..2134393f 100644 --- a/deployments/goerli/LpTokenFactory.json +++ b/deployments/goerli/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "530f09405f9b997fd4129db468c279d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x24b04b8aacaaf1a4a0719117b29c9c3647b1f479c5ac2a60f5ff1bb6d839c238\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x24b04b8aacaaf1a4a0719117b29c9c3647b1f479c5ac2a60f5ff1bb6d839c238\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220ae1af4c6ba3b3ddfee5c0c252ca16095fdb12c3dc044ba3635160120a67b04a064736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212205257870f7ee952c4687aa9c1fe4b37ed2a1c8dda16b3b45b15c1a60fa462ee5c64736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220ae1af4c6ba3b3ddfee5c0c252ca16095fdb12c3dc044ba3635160120a67b04a064736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212205257870f7ee952c4687aa9c1fe4b37ed2a1c8dda16b3b45b15c1a60fa462ee5c64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/ZkSync_Adapter.json b/deployments/goerli/ZkSync_Adapter.json index e12287f2..07a3d30f 100644 --- a/deployments/goerli/ZkSync_Adapter.json +++ b/deployments/goerli/ZkSync_Adapter.json @@ -221,7 +221,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "4972f5cae7c6e9deea3ed342ae0a0eeb", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"}],\"name\":\"ZkSyncMessageRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ergsLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkErc20Bridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkEthBridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkSync\",\"outputs\":[{\"internalType\":\"contract ZkSyncLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to ZkSync.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/ZkSync_Adapter.sol\":\"ZkSync_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\n// SPDX-License-Identifier: MIT OR Apache-2.0\\n\\n\\n\\n/// @notice Priority Operation container\\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\\nstruct PriorityOperation {\\n bytes32 canonicalTxHash;\\n uint64 expirationBlock;\\n uint192 layer2Tip;\\n}\\n\\n/// @notice A structure that stores all priority operations by ID\\n/// used for easy acceptance as an argument in functions\\nstruct StoredOperations {\\n mapping(uint64 => PriorityOperation) inner;\\n}\\n\\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\\nenum OpTree {\\n Full,\\n Rollup\\n}\\n\\n/// @notice Priority operations queue type\\nenum QueueType {\\n Deque,\\n HeapBuffer,\\n Heap\\n}\\n\",\"keccak256\":\"0x2ef35aee4840baf29036547cd7ec428889eaa17786c621d772a1bd4940ada2c2\",\"license\":\"MIT OR Apache-2.0\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/ZkSync_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// Importing `Operations` contract which has the `QueueType` type\\nimport \\\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\\\";\\n\\ninterface ZkSyncLike {\\n function requestL2Transaction(\\n address _contractAddressL2,\\n bytes calldata _calldata,\\n uint256 _ergsLimit,\\n bytes[] calldata _factoryDeps,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\ninterface ZkBridgeLike {\\n function deposit(\\n address _to,\\n address _l1Token,\\n uint256 _amount,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to ZkSync.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract ZkSync_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\\n \\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\\n // (ergs = gas on ZkSync) and the calldata length. More details here:\\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\\n\\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\\n uint256 public immutable l2GasPrice = 1e9;\\n\\n uint32 public immutable ergsLimit = 1_000_000;\\n\\n // Hardcode WETH address for L1 since it will not change:\\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\\n\\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\\n // redeployed in the event that the following addresses change.\\n\\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\\n\\n event ZkSyncMessageRelayed(bytes32 txHash);\\n\\n /**\\n * @notice Send cross-chain message to target on ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \\n * will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // Parameters passed to requestL2Transaction:\\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\\n // same way as on Ethereum.\\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\\n // QueueType.Deque should always be supplied.\\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\\n target,\\n message,\\n ergsLimit,\\n new bytes[](0),\\n QueueType.Deque\\n );\\n\\n emit MessageRelayed(target, message);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Bridge tokens to ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \\n * or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\\n // cost.\\n bytes32 txHash;\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2GasPrice * ergsLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x48c1425675f529b41bc65ba300b2c0fd5b9aa3dd5e4a859fb93e12bc878f5740\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"}],\"name\":\"ZkSyncMessageRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ergsLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkErc20Bridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkEthBridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkSync\",\"outputs\":[{\"internalType\":\"contract ZkSyncLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to ZkSync.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/ZkSync_Adapter.sol\":\"ZkSync_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\n// SPDX-License-Identifier: MIT OR Apache-2.0\\n\\n\\n\\n/// @notice Priority Operation container\\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\\nstruct PriorityOperation {\\n bytes32 canonicalTxHash;\\n uint64 expirationBlock;\\n uint192 layer2Tip;\\n}\\n\\n/// @notice A structure that stores all priority operations by ID\\n/// used for easy acceptance as an argument in functions\\nstruct StoredOperations {\\n mapping(uint64 => PriorityOperation) inner;\\n}\\n\\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\\nenum OpTree {\\n Full,\\n Rollup\\n}\\n\\n/// @notice Priority operations queue type\\nenum QueueType {\\n Deque,\\n HeapBuffer,\\n Heap\\n}\\n\",\"keccak256\":\"0x2ef35aee4840baf29036547cd7ec428889eaa17786c621d772a1bd4940ada2c2\",\"license\":\"MIT OR Apache-2.0\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/ZkSync_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// Importing `Operations` contract which has the `QueueType` type\\nimport \\\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\\\";\\n\\ninterface ZkSyncLike {\\n function requestL2Transaction(\\n address _contractAddressL2,\\n bytes calldata _calldata,\\n uint256 _ergsLimit,\\n bytes[] calldata _factoryDeps,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\ninterface ZkBridgeLike {\\n function deposit(\\n address _to,\\n address _l1Token,\\n uint256 _amount,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to ZkSync.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract ZkSync_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\\n \\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\\n // (ergs = gas on ZkSync) and the calldata length. More details here:\\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\\n\\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\\n uint256 public immutable l2GasPrice = 1e9;\\n\\n uint32 public immutable ergsLimit = 1_000_000;\\n\\n // Hardcode WETH address for L1 since it will not change:\\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\\n\\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\\n // redeployed in the event that the following addresses change.\\n\\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\\n\\n event ZkSyncMessageRelayed(bytes32 txHash);\\n\\n /**\\n * @notice Send cross-chain message to target on ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \\n * will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // Parameters passed to requestL2Transaction:\\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\\n // same way as on Ethereum.\\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\\n // QueueType.Deque should always be supplied.\\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\\n target,\\n message,\\n ergsLimit,\\n new bytes[](0),\\n QueueType.Deque\\n );\\n\\n emit MessageRelayed(target, message);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Bridge tokens to ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \\n * or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\\n // cost.\\n bytes32 txHash;\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2GasPrice * ergsLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x48c1425675f529b41bc65ba300b2c0fd5b9aa3dd5e4a859fb93e12bc878f5740\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052633b9aca00608052620f424060a05273b4fbf271143f4fbf7b91a5ded31805e42b2208d660c05273a0f968eba6bbd08f28dc061c7856c1572598339560e052737786255495348c08f82c09c82352019fade3bf296101005273cbebcd41ceabbc85da9bb67527f58d69ad4dfff56101205234801561008257600080fd5b5060805160a05160c05160e05161010051610120516110e46101106000396000818161018c01526103b70152600081816102280152818161048801526104ea0152600081816101c0015261062d01526000818160d5015281816102c4015261034401526000818161012e0152818161026901526106570152600081816101f4015261028b01526110e46000f3fe6080604052600436106100965760003560e01c80636bbc6c3d116100695780639ae366851161004e5780639ae36685146101e2578063bb3e04b514610216578063e6eb8ade1461024a57600080fd5b80636bbc6c3d1461017a5780637c19f005146101ae57600080fd5b806308f1ed151461009b578063146bf4b1146100c35780633ab307681461011c57806352c8c75c14610165575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b34801561012857600080fd5b506101507f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b610178610173366004610c79565b6102b4565b005b34801561018657600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ba57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ee57600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561022257600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b610178610258366004610cf5565b610608565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e04565b905090565b60006102be610784565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361046c576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039d57600080fd5b505af11580156103b1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637f63f61885846103fd9190610e41565b8560008860006040518663ffffffff1660e01b81526004016104229493929190610e94565b60206040518083038185885af1158015610440573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104659190610ed6565b905061056e565b6104ad73ffffffffffffffffffffffffffffffffffffffff87167f000000000000000000000000000000000000000000000000000000000000000086610802565b6040517f7f63f61800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637f63f6189084906105289087908b908a90600090600401610e94565b60206040518083038185885af1158015610546573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061056b9190610ed6565b90505b6040805173ffffffffffffffffffffffffffffffffffffffff888116825287811660208301528183018790528516606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a1505050505050565b6000610612610784565b9050600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663b4848df58386867f0000000000000000000000000000000000000000000000000000000000000000866040519080825280602002602001820160405280156106aa57816020015b60608152602001906001900390816106955790505b5060006040518763ffffffff1660e01b81526004016106cd959493929190610f65565b60206040518083038185885af11580156106eb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107109190610ed6565b90507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4848460405161074392919061102e565b60405180910390a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a150505050565b600061078e61025d565b9050804710156107ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089d9190610ed6565b6108a79190610e41565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061093790859061093d565b50505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4e9092919063ffffffff16565b805190915015610a4957808060200190518101906109bd919061105d565b610a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107f6565b505050565b6060610a5d8484600085610a67565b90505b9392505050565b606082471015610af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107f6565b73ffffffffffffffffffffffffffffffffffffffff85163b610b77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107f6565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba0919061107f565b60006040518083038185875af1925050503d8060008114610bdd576040519150601f19603f3d011682016040523d82523d6000602084013e610be2565b606091505b5091509150610bf2828286610bfd565b979650505050505050565b60608315610c0c575081610a60565b825115610c1c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f6919061109b565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7457600080fd5b919050565b60008060008060808587031215610c8f57600080fd5b610c9885610c50565b9350610ca660208601610c50565b925060408501359150610cbb60608601610c50565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0857600080fd5b610d1183610c50565b9150602083013567ffffffffffffffff80821115610d2e57600080fd5b818501915085601f830112610d4257600080fd5b813581811115610d5457610d54610cc6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9a57610d9a610cc6565b81604052828152886020848701011115610db357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e3c57610e3c610dd5565b500290565b60008219821115610e5457610e54610dd5565b500190565b60038110610e90577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b73ffffffffffffffffffffffffffffffffffffffff8581168252841660208201526040810183905260808101610ecd6060830184610e59565b95945050505050565b600060208284031215610ee857600080fd5b5051919050565b60005b83811015610f0a578181015183820152602001610ef2565b838111156109375750506000910152565b60008151808452610f33816020860160208601610eef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff861681526000602060a081840152610f9560a0840188610f1b565b63ffffffff871660408501528381036060850152855180825282820190600581901b8301840184890160005b8381101561100d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552610ffb838351610f1b565b94870194925090860190600101610fc1565b505080955050505050506110246080830184610e59565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5d6040830184610f1b565b60006020828403121561106f57600080fd5b81518015158114610a6057600080fd5b60008251611091818460208701610eef565b9190910192915050565b602081526000610a606020830184610f1b56fea2646970667358221220f2d66b26ee0770e83f57c27ccb80c0dc4c72c5b22119ead93d7474349789c95264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80636bbc6c3d116100695780639ae366851161004e5780639ae36685146101e2578063bb3e04b514610216578063e6eb8ade1461024a57600080fd5b80636bbc6c3d1461017a5780637c19f005146101ae57600080fd5b806308f1ed151461009b578063146bf4b1146100c35780633ab307681461011c57806352c8c75c14610165575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b34801561012857600080fd5b506101507f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b610178610173366004610c79565b6102b4565b005b34801561018657600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ba57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ee57600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561022257600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b610178610258366004610cf5565b610608565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e04565b905090565b60006102be610784565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361046c576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039d57600080fd5b505af11580156103b1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637f63f61885846103fd9190610e41565b8560008860006040518663ffffffff1660e01b81526004016104229493929190610e94565b60206040518083038185885af1158015610440573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104659190610ed6565b905061056e565b6104ad73ffffffffffffffffffffffffffffffffffffffff87167f000000000000000000000000000000000000000000000000000000000000000086610802565b6040517f7f63f61800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637f63f6189084906105289087908b908a90600090600401610e94565b60206040518083038185885af1158015610546573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061056b9190610ed6565b90505b6040805173ffffffffffffffffffffffffffffffffffffffff888116825287811660208301528183018790528516606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a1505050505050565b6000610612610784565b9050600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663b4848df58386867f0000000000000000000000000000000000000000000000000000000000000000866040519080825280602002602001820160405280156106aa57816020015b60608152602001906001900390816106955790505b5060006040518763ffffffff1660e01b81526004016106cd959493929190610f65565b60206040518083038185885af11580156106eb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107109190610ed6565b90507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4848460405161074392919061102e565b60405180910390a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a150505050565b600061078e61025d565b9050804710156107ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089d9190610ed6565b6108a79190610e41565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061093790859061093d565b50505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4e9092919063ffffffff16565b805190915015610a4957808060200190518101906109bd919061105d565b610a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107f6565b505050565b6060610a5d8484600085610a67565b90505b9392505050565b606082471015610af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107f6565b73ffffffffffffffffffffffffffffffffffffffff85163b610b77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107f6565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba0919061107f565b60006040518083038185875af1925050503d8060008114610bdd576040519150601f19603f3d011682016040523d82523d6000602084013e610be2565b606091505b5091509150610bf2828286610bfd565b979650505050505050565b60608315610c0c575081610a60565b825115610c1c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f6919061109b565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7457600080fd5b919050565b60008060008060808587031215610c8f57600080fd5b610c9885610c50565b9350610ca660208601610c50565b925060408501359150610cbb60608601610c50565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0857600080fd5b610d1183610c50565b9150602083013567ffffffffffffffff80821115610d2e57600080fd5b818501915085601f830112610d4257600080fd5b813581811115610d5457610d54610cc6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9a57610d9a610cc6565b81604052828152886020848701011115610db357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e3c57610e3c610dd5565b500290565b60008219821115610e5457610e54610dd5565b500190565b60038110610e90577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b73ffffffffffffffffffffffffffffffffffffffff8581168252841660208201526040810183905260808101610ecd6060830184610e59565b95945050505050565b600060208284031215610ee857600080fd5b5051919050565b60005b83811015610f0a578181015183820152602001610ef2565b838111156109375750506000910152565b60008151808452610f33816020860160208601610eef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff861681526000602060a081840152610f9560a0840188610f1b565b63ffffffff871660408501528381036060850152855180825282820190600581901b8301840184890160005b8381101561100d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552610ffb838351610f1b565b94870194925090860190600101610fc1565b505080955050505050506110246080830184610e59565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5d6040830184610f1b565b60006020828403121561106f57600080fd5b81518015158114610a6057600080fd5b60008251611091818460208701610eef565b9190910192915050565b602081526000610a606020830184610f1b56fea2646970667358221220f2d66b26ee0770e83f57c27ccb80c0dc4c72c5b22119ead93d7474349789c95264736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json b/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json index 870df190..343a79c6 100644 --- a/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json +++ b/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json b/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json index 6cdc08c4..4746a4a5 100644 --- a/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json +++ b/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -26,76 +26,76 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n address public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n address public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _zkErc20Bridge,\n address _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(address _zkErc20Bridge, address _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n ZkBridgeLike(relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge)\n .withdraw(\n hubPool, \n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? address(0) : relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(address _zkErc20Bridge, address _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n address public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n address public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _zkErc20Bridge,\n address _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(address _zkErc20Bridge, address _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n ZkBridgeLike(relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge)\n .withdraw(\n hubPool, \n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? address(0) : relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(address _zkErc20Bridge, address _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -110,13 +110,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -125,58 +125,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n \n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n \n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -185,22 +185,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json b/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json index 7aa31929..d083c08e 100644 --- a/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json +++ b/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,58 +131,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -191,25 +191,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n // Addresses that can claim on user's behalf. Useful to get around the requirement that claim recipient\n // must also be claimer.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender or claimer must be whitelisted.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n if (!whitelistedClaimers[msg.sender]) {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender or caller must be whitelisted.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(whitelistedClaimers[msg.sender] || _claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n // Addresses that can claim on user's behalf. Useful to get around the requirement that claim recipient\n // must also be claimer.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender or claimer must be whitelisted.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n if (!whitelistedClaimers[msg.sender]) {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender or caller must be whitelisted.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(whitelistedClaimers[msg.sender] || _claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json b/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json index c1ab45cf..6554b649 100644 --- a/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json +++ b/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -26,13 +26,13 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -74,37 +74,37 @@ "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/interfaces/IERC1271.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title MockERC1271\n * @notice Implements mocked ERC1271 contract for testing.\n */\ncontract MockERC1271 is IERC1271, Ownable {\n constructor(address originalOwner) {\n transferOwnership(originalOwner);\n }\n\n function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) {\n return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);\n }\n}\n" }, "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "contracts/BondToken.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./interfaces/HubPoolInterface.sol\";\nimport \"./external/WETH9.sol\";\n\ninterface ExtendedHubPoolInterface is HubPoolInterface {\n // Specify the automatically-implemented rootBundleProposal() getter.\n function rootBundleProposal() external pure returns (HubPoolInterface.RootBundle memory);\n}\n\n/**\n * @notice Across Bond Token (ABT).\n * ABT is a simple deposit contract based on WETH9. ABT is issued proportionally to any address that deposits Ether. It\n * imposes address-based permissioning on the WETH9 transferFrom() function in order to constrain the movement of ABT\n * into the Across v2 HubPool contract. When configured as the required HubPool bond token, ABT can dramatically reduce\n * the attack surface of the HubPool by requiring that addresses are explicitly approved before they can successfully\n * submit a root bundle proposal. The address-based permissioning does not constrain transfers that are needed to dispute\n * a root bundle proposal, so the ability of decentralised/unknown actors to dispute is unaffected.\n */\ncontract BondToken is WETH9, Ownable {\n using Address for address;\n\n ExtendedHubPoolInterface public immutable hubPool;\n\n /**\n * @notice Addresses that are permitted to make HubPool root bundle proposals.\n */\n mapping(address => bool) public proposers;\n\n /**\n * @notice Emitted on proposer permissions update.\n */\n event ProposerModified(address proposer, bool enabled);\n\n /**\n * @notice BondToken constructor.\n * @param _hubPool Address of the target HubPool contract.\n */\n constructor(ExtendedHubPoolInterface _hubPool) {\n name = \"Across Bond Token\";\n symbol = \"ABT\";\n hubPool = _hubPool;\n }\n\n /**\n * @notice Enable or disable an address as an allowed proposer. Emits a \"ProposerModified\" event on completion.\n * @param proposer Proposer address to modify.\n * @param enabled Boolean controlling whether the address is permitted to propose.\n */\n function setProposer(address proposer, bool enabled) external onlyOwner {\n proposers[proposer] = enabled;\n emit ProposerModified(proposer, enabled);\n }\n\n /**\n * @notice Transfer amt from src to dst. Prevents unauthorised root bundle proposals by blocking transfers to the\n * HubPool under the following conditions:\n * - The src address is not a pre-approved proposer, *and*\n * - The src address is the current proposer of a HubPool root bundle.\n * Falls back to the base implementation after verifying that the transfer is permitted.\n * @dev The require(..., \"Transfer not permitted\") statement is dependent on the internal ordering of HubPool\n * proposedRootBundle state variable updates, relative to calling bondToken.safeTransferFrom(). Changing the order\n * of HubPool actions may invalidate this verification. BondToken tests are implemented to detect this.\n * @param src Source address.\n * @param dst Destination address.\n * @param amt Amount to transfer.\n * @return True on success.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amt\n ) public override returns (bool) {\n if (dst == address(hubPool)) {\n require(proposers[src] || hubPool.rootBundleProposal().proposer != src, \"Transfer not permitted\");\n }\n return super.transferFrom(src, dst, amt);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./interfaces/HubPoolInterface.sol\";\nimport \"./external/WETH9.sol\";\n\ninterface ExtendedHubPoolInterface is HubPoolInterface {\n // Specify the automatically-implemented rootBundleProposal() getter.\n function rootBundleProposal() external pure returns (HubPoolInterface.RootBundle memory);\n}\n\n/**\n * @notice Across Bond Token (ABT).\n * ABT is a simple deposit contract based on WETH9. ABT is issued proportionally to any address that deposits Ether. It\n * imposes address-based permissioning on the WETH9 transferFrom() function in order to constrain the movement of ABT\n * into the Across v2 HubPool contract. When configured as the required HubPool bond token, ABT can dramatically reduce\n * the attack surface of the HubPool by requiring that addresses are explicitly approved before they can successfully\n * submit a root bundle proposal. The address-based permissioning does not constrain transfers that are needed to dispute\n * a root bundle proposal, so the ability of decentralised/unknown actors to dispute is unaffected.\n */\ncontract BondToken is WETH9, Ownable {\n using Address for address;\n\n ExtendedHubPoolInterface public immutable hubPool;\n\n /**\n * @notice Addresses that are permitted to make HubPool root bundle proposals.\n */\n mapping(address => bool) public proposers;\n\n /**\n * @notice Emitted on proposer permissions update.\n */\n event ProposerModified(address proposer, bool enabled);\n\n /**\n * @notice BondToken constructor.\n * @param _hubPool Address of the target HubPool contract.\n */\n constructor(ExtendedHubPoolInterface _hubPool) {\n name = \"Across Bond Token\";\n symbol = \"ABT\";\n hubPool = _hubPool;\n }\n\n /**\n * @notice Enable or disable an address as an allowed proposer. Emits a \"ProposerModified\" event on completion.\n * @param proposer Proposer address to modify.\n * @param enabled Boolean controlling whether the address is permitted to propose.\n */\n function setProposer(address proposer, bool enabled) external onlyOwner {\n proposers[proposer] = enabled;\n emit ProposerModified(proposer, enabled);\n }\n\n /**\n * @notice Transfer amt from src to dst. Prevents unauthorised root bundle proposals by blocking transfers to the\n * HubPool under the following conditions:\n * - The src address is not a pre-approved proposer, *and*\n * - The src address is the current proposer of a HubPool root bundle.\n * Falls back to the base implementation after verifying that the transfer is permitted.\n * @dev The require(..., \"Transfer not permitted\") statement is dependent on the internal ordering of HubPool\n * proposedRootBundle state variable updates, relative to calling bondToken.safeTransferFrom(). Changing the order\n * of HubPool actions may invalidate this verification. BondToken tests are implemented to detect this.\n * @param src Source address.\n * @param dst Destination address.\n * @param amt Amount to transfer.\n * @return True on success.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amt\n ) public override returns (bool) {\n if (dst == address(hubPool)) {\n require(proposers[src] || hubPool.rootBundleProposal().proposer != src, \"Transfer not permitted\");\n }\n return super.transferFrom(src, dst, amt);\n }\n}\n" }, "contracts/interfaces/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/external/WETH9.sol": { "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n/**\n * Copyright (C) 2015, 2016, 2017 Dapphub\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n/**\n * Imported as at commit 33d01d471437e1ab6861e4545ea4bb3895fd4d74 from:\n * UMAprotocol/protocol/packages/core/contracts/financial-templates/common/WETH9.sol\n * Changes applied post-import:\n * - Corrected SPDX-License-Identifier & reinstated GPLv3 license header.\n * - Permit transferFrom() to be overridden by marking it virtual.\n */\n\npragma solidity ^0.8.0;\n\ncontract WETH9 {\n string public name = \"Wrapped Ether\";\n string public symbol = \"WETH\";\n uint8 public decimals = 18;\n\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n receive() external payable {\n deposit();\n }\n\n fallback() external payable {\n deposit();\n }\n\n function deposit() public payable {\n balanceOf[msg.sender] += msg.value;\n emit Deposit(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) public {\n require(balanceOf[msg.sender] >= wad);\n balanceOf[msg.sender] -= wad;\n payable(msg.sender).transfer(wad);\n emit Withdrawal(msg.sender, wad);\n }\n\n function totalSupply() public view returns (uint256) {\n return address(this).balance;\n }\n\n function approve(address guy, uint256 wad) public returns (bool) {\n allowance[msg.sender][guy] = wad;\n emit Approval(msg.sender, guy, wad);\n return true;\n }\n\n function transfer(address dst, uint256 wad) public returns (bool) {\n return transferFrom(msg.sender, dst, wad);\n }\n\n /**\n * @dev Local change: marked virtual to allow overriding.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) public virtual returns (bool) {\n require(balanceOf[src] >= wad);\n\n if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) {\n require(allowance[src][msg.sender] >= wad);\n allowance[src][msg.sender] -= wad;\n }\n\n balanceOf[src] -= wad;\n balanceOf[dst] += wad;\n\n emit Transfer(src, dst, wad);\n\n return true;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../interfaces/HubPoolInterface.sol\";\nimport \"../interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowFill,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowFill, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../interfaces/HubPoolInterface.sol\";\nimport \"../interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowFill,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowFill, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./interfaces/HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./interfaces/HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index);\n }\n}\n" }, "contracts/interfaces/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n // This tracks the number of identical refunds that have been requested.\n // The intention is to allow an off-chain system to know when this could be a duplicate and ensure that the other\n // requests are known and accounted for.\n mapping(bytes32 => uint256) public refundsRequested;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n // Note: this needs to be larger than the max transfer size to ensure that all slow fills are fillable, even if\n // their fees are negative.\n // It's important that it isn't too large, however, as it should be multipliable by ~2e18 without overflowing.\n // 1e40 * 2e18 = 2e58 << 2^255 ~= 5e76\n uint256 public constant SLOW_FILL_MAX_TOKENS_TO_SEND = 1e40;\n\n // Set max payout adjustment to something\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 indexed destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n event RefundRequested(\n address indexed relayer,\n address refundToken,\n uint256 amount,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n uint256 fillBlock,\n uint256 previousIdenticalRequests\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n /**\n * @notice Represents data used to fill a deposit.\n * @param relay Relay containing original data linked to deposit. Contains fields that can be\n * overridden by other parameters in the RelayExecution struct.\n * @param relayHash Hash of the relay data.\n * @param updatedRelayerFeePct Actual relayer fee pct to use for this relay.\n * @param updatedRecipient Actual recipient to use for this relay.\n * @param updatedMessage Actual message to use for this relay.\n * @param repaymentChainId Chain ID of the network that the relayer will receive refunds on.\n * @param maxTokensToSend Max number of tokens to pull from relayer.\n * @param maxCount Max count to protect the relayer from frontrunning.\n * @param slowFill Whether this is a slow fill.\n * @param payoutAdjustmentPct Adjustment to the payout amount. Can be used to increase or decrease the payout to\n * allow for rewards or penalties. Used in slow fills.\n */\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * @notice Packs together information to include in FilledRelay event.\n * @dev This struct is emitted as opposed to its constituent parameters due to the limit on number of\n * parameters in an event.\n * @param recipient Recipient of the relayed funds.\n * @param message Message included in the relay.\n * @param relayerFeePct Relayer fee pct used for this relay.\n * @param isSlowRelay Whether this is a slow relay.\n * @param payoutAdjustmentPct Adjustment to the payout amount.\n */\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects `deposit()` but not `speedUpDeposit()`, so that existing deposits can be sped up and still\n * relayed.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n /**\n * @notice Pauses fill-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects fillRelayWithUpdatedDeposit() and fillRelay().\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit FundsDeposited(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(SignedMath.abs(updatedRelayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpDeposit().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Caller signals to the system that they want a refund on this chain, which they set as the\n * `repaymentChainId` on the original fillRelay() call on the `destinationChainId`. An observer should be\n * be able to 1-to-1 match the emitted RefundRequested event with the FilledRelay event on the `destinationChainId`.\n * @dev This function could be used to artificially inflate the `fillCounter`, allowing the caller to \"frontrun\"\n * and cancel pending fills in the mempool. This would in the worst case censor fills at the cost of the caller's\n * gas costs. We don't view this as a major issue as the fill can be resubmitted and obtain the same incentive,\n * since incentives are based on validated refunds and would ignore these censoring attempts. This is no\n * different from calling `fillRelay` and setting msg.sender = recipient.\n * @dev Caller needs to pass in `fillBlock` that the FilledRelay event was emitted on the `destinationChainId`.\n * This is to make it hard to request a refund before a fill has been mined and to make lookups of the original\n * fill as simple as possible.\n * @param refundToken This chain's token equivalent for original fill destination token.\n * @param amount Original deposit amount.\n * @param originChainId Original origin chain ID.\n * @param destinationChainId Original destination chain ID.\n * @param realizedLpFeePct Original realized LP fee %.\n * @param depositId Original deposit ID.\n * @param maxCount Max count to protect the refund recipient from frontrunning.\n */\n function requestRefund(\n address refundToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 depositId,\n uint256 fillBlock,\n uint256 maxCount\n ) external nonReentrant {\n // Prevent unrealistic amounts from increasing fill counter too high.\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[refundToken] <= maxCount, \"Above max count\");\n\n // Track duplicate refund requests.\n bytes32 refundHash = keccak256(\n abi.encode(\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock\n )\n );\n\n // Track duplicate requests so that an offchain actor knows if an identical request has already been made.\n // If so, it can check to ensure that that request was thrown out as invalid before honoring the duplicate.\n // In particular, this is meant to handle odd cases where an initial request is invalidated based on\n // timing, but can be validated by a later, identical request.\n uint256 previousIdenticalRequests = refundsRequested[refundHash]++;\n\n // Refund will take tokens out of this pool, increment the fill counter. This function should only be\n // called if a relayer from destinationChainId wants to take a refund on this chain, a different chain.\n // This type of repayment should only be possible for full fills, so the starting fill amount should\n // always be 0. Also, just like in _fillRelay we should revert if the first fill pre fees rounds to 0,\n // and in this case `amount` == `fillAmountPreFees`.\n require(amount > 0, \"Amount must be > 0\");\n _updateCountFromFill(\n 0,\n true, // The refund is being requested here, so it is local.\n amount,\n realizedLpFeePct,\n refundToken,\n false // Slow fills should never match with a Refund. This should be enforced by off-chain bundle builders.\n );\n\n emit RefundRequested(\n // Set caller as relayer. If caller is not relayer from destination chain that originally sent\n // fill, then off-chain validator should discard this refund attempt.\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock,\n previousIdenticalRequests\n );\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: SLOW_FILL_MAX_TOKENS_TO_SEND,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n // This is equivalent to the amount to be sent by the relayer before fees have been taken out.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If fill amount minus fees, which is possible with small fill amounts and negative fees, then\n // revert.\n require(fillAmountPreFees > 0, \"fill amount pre fees is 0\");\n\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n }\n\n // Apply post-fees computation to amount that relayer will send to user. Rounding errors are possible\n // when computing fillAmountPreFees and then amountToSend, and we just want to enforce that\n // the error added to amountToSend is consistently applied to partial and full fills.\n uint256 amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n // This can only happen in a slow fill, where the contract is funding the relay.\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Allow the payout adjustment to go up to 1000% (i.e. 11x).\n // This is a sanity check to ensure the payouts do not grow too large via some sort of issue in bundle\n // construction.\n require(relayExecution.payoutAdjustmentPct <= 100e18, \"payoutAdjustmentPct too large\");\n\n // Note: since _computeAmountPostFees is typically intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n\n // Note: this error should never happen, since the maxTokensToSend is expected to be set much higher than\n // the amount, but it is here as a sanity check.\n require(amountToSend <= relayExecution.maxTokensToSend, \"Somehow hit maxTokensToSend!\");\n }\n\n // Since the first partial fill is used to update the fill counter for the entire refund amount, we don't have\n // a simple way to handle the case where follow-up partial fills take repayment on different chains. We'd\n // need a way to decrement the fill counter in this case (or increase deposit counter) to ensure that users\n // have adequate frontrunning protections.\n // Instead of adding complexity, we require that all partial fills set repayment chain equal to destination chain.\n // Note: .slowFill is checked because slow fills set repaymentChainId to 0.\n bool localRepayment = relayExecution.repaymentChainId == relayExecution.relay.destinationChainId;\n require(\n localRepayment || relayExecution.relay.amount == fillAmountPreFees || relayExecution.slowFill,\n \"invalid repayment chain\"\n );\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n localRepayment,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n bool localRepayment,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, a first partial fill with repayment on another chain, or a partial fill has already happened, do nothing, as these\n // should not impact the count. Initial 0-fills will not reach this part of the code.\n if (useContractFunds || startingFillAmount > 0 || !localRepayment) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n // This tracks the number of identical refunds that have been requested.\n // The intention is to allow an off-chain system to know when this could be a duplicate and ensure that the other\n // requests are known and accounted for.\n mapping(bytes32 => uint256) public refundsRequested;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n // Note: this needs to be larger than the max transfer size to ensure that all slow fills are fillable, even if\n // their fees are negative.\n // It's important that it isn't too large, however, as it should be multipliable by ~2e18 without overflowing.\n // 1e40 * 2e18 = 2e58 << 2^255 ~= 5e76\n uint256 public constant SLOW_FILL_MAX_TOKENS_TO_SEND = 1e40;\n\n // Set max payout adjustment to something\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 indexed destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n event RefundRequested(\n address indexed relayer,\n address refundToken,\n uint256 amount,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n uint256 fillBlock,\n uint256 previousIdenticalRequests\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n /**\n * @notice Represents data used to fill a deposit.\n * @param relay Relay containing original data linked to deposit. Contains fields that can be\n * overridden by other parameters in the RelayExecution struct.\n * @param relayHash Hash of the relay data.\n * @param updatedRelayerFeePct Actual relayer fee pct to use for this relay.\n * @param updatedRecipient Actual recipient to use for this relay.\n * @param updatedMessage Actual message to use for this relay.\n * @param repaymentChainId Chain ID of the network that the relayer will receive refunds on.\n * @param maxTokensToSend Max number of tokens to pull from relayer.\n * @param maxCount Max count to protect the relayer from frontrunning.\n * @param slowFill Whether this is a slow fill.\n * @param payoutAdjustmentPct Adjustment to the payout amount. Can be used to increase or decrease the payout to\n * allow for rewards or penalties. Used in slow fills.\n */\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * @notice Packs together information to include in FilledRelay event.\n * @dev This struct is emitted as opposed to its constituent parameters due to the limit on number of\n * parameters in an event.\n * @param recipient Recipient of the relayed funds.\n * @param message Message included in the relay.\n * @param relayerFeePct Relayer fee pct used for this relay.\n * @param isSlowRelay Whether this is a slow relay.\n * @param payoutAdjustmentPct Adjustment to the payout amount.\n */\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects `deposit()` but not `speedUpDeposit()`, so that existing deposits can be sped up and still\n * relayed.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n /**\n * @notice Pauses fill-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects fillRelayWithUpdatedDeposit() and fillRelay().\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit FundsDeposited(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(SignedMath.abs(updatedRelayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpDeposit().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Caller signals to the system that they want a refund on this chain, which they set as the\n * `repaymentChainId` on the original fillRelay() call on the `destinationChainId`. An observer should be\n * be able to 1-to-1 match the emitted RefundRequested event with the FilledRelay event on the `destinationChainId`.\n * @dev This function could be used to artificially inflate the `fillCounter`, allowing the caller to \"frontrun\"\n * and cancel pending fills in the mempool. This would in the worst case censor fills at the cost of the caller's\n * gas costs. We don't view this as a major issue as the fill can be resubmitted and obtain the same incentive,\n * since incentives are based on validated refunds and would ignore these censoring attempts. This is no\n * different from calling `fillRelay` and setting msg.sender = recipient.\n * @dev Caller needs to pass in `fillBlock` that the FilledRelay event was emitted on the `destinationChainId`.\n * This is to make it hard to request a refund before a fill has been mined and to make lookups of the original\n * fill as simple as possible.\n * @param refundToken This chain's token equivalent for original fill destination token.\n * @param amount Original deposit amount.\n * @param originChainId Original origin chain ID.\n * @param destinationChainId Original destination chain ID.\n * @param realizedLpFeePct Original realized LP fee %.\n * @param depositId Original deposit ID.\n * @param maxCount Max count to protect the refund recipient from frontrunning.\n */\n function requestRefund(\n address refundToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 depositId,\n uint256 fillBlock,\n uint256 maxCount\n ) external nonReentrant {\n // Prevent unrealistic amounts from increasing fill counter too high.\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[refundToken] <= maxCount, \"Above max count\");\n\n // Track duplicate refund requests.\n bytes32 refundHash = keccak256(\n abi.encode(\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock\n )\n );\n\n // Track duplicate requests so that an offchain actor knows if an identical request has already been made.\n // If so, it can check to ensure that that request was thrown out as invalid before honoring the duplicate.\n // In particular, this is meant to handle odd cases where an initial request is invalidated based on\n // timing, but can be validated by a later, identical request.\n uint256 previousIdenticalRequests = refundsRequested[refundHash]++;\n\n // Refund will take tokens out of this pool, increment the fill counter. This function should only be\n // called if a relayer from destinationChainId wants to take a refund on this chain, a different chain.\n // This type of repayment should only be possible for full fills, so the starting fill amount should\n // always be 0. Also, just like in _fillRelay we should revert if the first fill pre fees rounds to 0,\n // and in this case `amount` == `fillAmountPreFees`.\n require(amount > 0, \"Amount must be > 0\");\n _updateCountFromFill(\n 0,\n true, // The refund is being requested here, so it is local.\n amount,\n realizedLpFeePct,\n refundToken,\n false // Slow fills should never match with a Refund. This should be enforced by off-chain bundle builders.\n );\n\n emit RefundRequested(\n // Set caller as relayer. If caller is not relayer from destination chain that originally sent\n // fill, then off-chain validator should discard this refund attempt.\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock,\n previousIdenticalRequests\n );\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: SLOW_FILL_MAX_TOKENS_TO_SEND,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n // This is equivalent to the amount to be sent by the relayer before fees have been taken out.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If fill amount minus fees, which is possible with small fill amounts and negative fees, then\n // revert.\n require(fillAmountPreFees > 0, \"fill amount pre fees is 0\");\n\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n }\n\n // Apply post-fees computation to amount that relayer will send to user. Rounding errors are possible\n // when computing fillAmountPreFees and then amountToSend, and we just want to enforce that\n // the error added to amountToSend is consistently applied to partial and full fills.\n uint256 amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n // This can only happen in a slow fill, where the contract is funding the relay.\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Allow the payout adjustment to go up to 1000% (i.e. 11x).\n // This is a sanity check to ensure the payouts do not grow too large via some sort of issue in bundle\n // construction.\n require(relayExecution.payoutAdjustmentPct <= 100e18, \"payoutAdjustmentPct too large\");\n\n // Note: since _computeAmountPostFees is typically intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n\n // Note: this error should never happen, since the maxTokensToSend is expected to be set much higher than\n // the amount, but it is here as a sanity check.\n require(amountToSend <= relayExecution.maxTokensToSend, \"Somehow hit maxTokensToSend!\");\n }\n\n // Since the first partial fill is used to update the fill counter for the entire refund amount, we don't have\n // a simple way to handle the case where follow-up partial fills take repayment on different chains. We'd\n // need a way to decrement the fill counter in this case (or increase deposit counter) to ensure that users\n // have adequate frontrunning protections.\n // Instead of adding complexity, we require that all partial fills set repayment chain equal to destination chain.\n // Note: .slowFill is checked because slow fills set repaymentChainId to 0.\n bool localRepayment = relayExecution.repaymentChainId == relayExecution.relay.destinationChainId;\n require(\n localRepayment || relayExecution.relay.amount == fillAmountPreFees || relayExecution.slowFill,\n \"invalid repayment chain\"\n );\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n localRepayment,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n bool localRepayment,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, a first partial fill with repayment on another chain, or a partial fill has already happened, do nothing, as these\n // should not impact the count. Initial 0-fills will not reach this part of the code.\n if (useContractFunds || startingFillAmount > 0 || !localRepayment) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/external/interfaces/WETH9Interface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Interface for the WETH9 contract.\n */\ninterface WETH9Interface {\n /**\n * @notice Burn Wrapped Ether and receive native Ether.\n * @param wad Amount of WETH to unwrap and send to caller.\n */\n function withdraw(uint256 wad) external;\n\n /**\n * @notice Lock native Ether and mint Wrapped Ether ERC20\n * @dev msg.value is amount of Wrapped Ether to mint/Ether to lock.\n */\n function deposit() external payable;\n\n /**\n * @notice Get balance of WETH held by `guy`.\n * @param guy Address to get balance of.\n * @return wad Amount of WETH held by `guy`.\n */\n function balanceOf(address guy) external view returns (uint256 wad);\n\n /**\n * @notice Transfer `wad` of WETH from caller to `guy`.\n * @param guy Address to send WETH to.\n * @param wad Amount of WETH to send.\n * @return ok True if transfer succeeded.\n */\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Interface for the WETH9 contract.\n */\ninterface WETH9Interface {\n /**\n * @notice Burn Wrapped Ether and receive native Ether.\n * @param wad Amount of WETH to unwrap and send to caller.\n */\n function withdraw(uint256 wad) external;\n\n /**\n * @notice Lock native Ether and mint Wrapped Ether ERC20\n * @dev msg.value is amount of Wrapped Ether to mint/Ether to lock.\n */\n function deposit() external payable;\n\n /**\n * @notice Get balance of WETH held by `guy`.\n * @param guy Address to get balance of.\n * @return wad Amount of WETH held by `guy`.\n */\n function balanceOf(address guy) external view returns (uint256 wad);\n\n /**\n * @notice Transfer `wad` of WETH from caller to `guy`.\n * @param guy Address to send WETH to.\n * @param wad Amount of WETH to send.\n * @return ok True if transfer succeeded.\n */\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" }, "contracts/upgradeable/MultiCallerUpgradeable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title MultiCallerUpgradeable\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title MultiCallerUpgradeable\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/upgradeable/EIP712CrossChainUpgradeable.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" @@ -167,58 +167,58 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, OwnableUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @dev crossDomainAdmin is unused on this contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __Ownable_init();\n __SpokePool_init(_initialDepositId, _hubPool, _hubPool, _wethAddress);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // The SpokePool deployed to the same network as the HubPool must be owned by the HubPool.\n // A core assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, OwnableUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @dev crossDomainAdmin is unused on this contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __Ownable_init();\n __SpokePool_init(_initialDepositId, _hubPool, _hubPool, _wethAddress);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // The SpokePool deployed to the same network as the HubPool must be owned by the HubPool.\n // A core assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20Upgradeable is IERC20Upgradeable {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9Interface public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9Interface _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n //slither-disable-next-line missing-zero-check\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n //slither-disable-next-line missing-zero-check\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20Upgradeable token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20Upgradeable token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n //slither-disable-next-line arbitrary-send-eth\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20Upgradeable is IERC20Upgradeable {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9Interface public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9Interface _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n //slither-disable-next-line missing-zero-check\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n //slither-disable-next-line missing-zero-check\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20Upgradeable token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20Upgradeable token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n //slither-disable-next-line arbitrary-send-eth\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ninterface LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ninterface LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice IFxMessageProcessor represents interface to process messages.\n */\ninterface IFxMessageProcessor {\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See comment for `_requireAdminSender` for more details.\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n */\n function initialize(\n uint32 _initialDepositId,\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild\n ) public initializer {\n callValidated = false;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wmaticAddress);\n polygonTokenBridger = _polygonTokenBridger;\n //slither-disable-next-line missing-zero-check\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n //slither-disable-next-line missing-zero-check\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n /// This is a safe delegatecall because its made to address(this) so there is no risk of delegating to a\n /// selfdestruct().\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(data);\n //slither-disable-end low-level-calls\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, rootMessageSender);\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Unlike other ERC20 transfers, Matic transfers from L1 -> L2 bridging don't result in an L2 call into\n * the contract receiving the tokens, so wrapping must be done via a separate transaction. In other words,\n * we can't rely upon a `fallback()` method being triggered to wrap MATIC upon receiving it.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n //slither-disable-next-line arbitrary-send-eth\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice IFxMessageProcessor represents interface to process messages.\n */\ninterface IFxMessageProcessor {\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See comment for `_requireAdminSender` for more details.\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n */\n function initialize(\n uint32 _initialDepositId,\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild\n ) public initializer {\n callValidated = false;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wmaticAddress);\n polygonTokenBridger = _polygonTokenBridger;\n //slither-disable-next-line missing-zero-check\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n //slither-disable-next-line missing-zero-check\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n /// This is a safe delegatecall because its made to address(this) so there is no risk of delegating to a\n /// selfdestruct().\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(data);\n //slither-disable-end low-level-calls\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, rootMessageSender);\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Unlike other ERC20 transfers, Matic transfers from L1 -> L2 bridging don't result in an L2 call into\n * the contract receiving the tokens, so wrapping must be done via a separate transaction. In other words,\n * we can't rely upon a `fallback()` method being triggered to wrap MATIC upon receiving it.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n //slither-disable-next-line arbitrary-send-eth\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9Interface public immutable l1Weth = WETH9Interface(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9Interface public immutable l1Weth = WETH9Interface(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n * This interface is implemented by an adapter contract that is deployed on L1.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n /**\n * @notice Send message to `target` on L2.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param target L2 address to send message to.\n * @param message Message to send to `target`.\n */\n function relayMessage(address target, bytes calldata message) external payable;\n\n /**\n * @notice Send `amount` of `l1Token` to `to` on L2. `l2Token` is the L2 address equivalent of `l1Token`.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param l1Token L1 token to bridge.\n * @param l2Token L2 token to receive.\n * @param amount Amount of `l1Token` to bridge.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n * This interface is implemented by an adapter contract that is deployed on L1.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n /**\n * @notice Send message to `target` on L2.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param target L2 address to send message to.\n * @param message Message to send to `target`.\n */\n function relayMessage(address target, bytes calldata message) external payable;\n\n /**\n * @notice Send `amount` of `l1Token` to `to` on L2. `l2Token` is the L2 address equivalent of `l1Token`.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param l1Token L1 token to bridge.\n * @param l2Token L2 token to receive.\n * @param amount Amount of `l1Token` to bridge.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Succinct_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/SuccinctInterfaces.sol\";\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Succinct_Adapter is AdapterInterface {\n ITelepathyBroadcaster public immutable succinctSourceAmb;\n uint16 public immutable destinationChainId;\n\n // Special Succinct event for additional tracking information.\n event SuccinctMessageRelayed(bytes32 messageRoot, uint16 destinationChainId, address target, bytes message);\n\n /**\n * @notice Constructs new Adapter.\n * @param _succinctSourceAmb address of the SourceAmb succinct contract for sending messages.\n * @param _destinationChainId chainId of the destination.\n */\n constructor(ITelepathyBroadcaster _succinctSourceAmb, uint16 _destinationChainId) {\n succinctSourceAmb = _succinctSourceAmb;\n destinationChainId = _destinationChainId;\n }\n\n /**\n * @notice Send cross-chain message to target on the destination.\n * @param target Contract on the destination that will receive the message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n bytes32 messageRoot = succinctSourceAmb.send(destinationChainId, target, message);\n\n // Note: this emits two events. MessageRelayed for the sake of compatibility with other adapters.\n // It emits SuccinctMessageRelayed to encode additional tracking information that is Succinct-specific.\n emit MessageRelayed(target, message);\n emit SuccinctMessageRelayed(messageRoot, destinationChainId, target, message);\n }\n\n /**\n * @notice No-op relay tokens method.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n // This method is intentionally left as a no-op.\n // If the adapter is intended to be able to relay tokens, this method should be overriden.\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/SuccinctInterfaces.sol\";\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Succinct_Adapter is AdapterInterface {\n ITelepathyBroadcaster public immutable succinctSourceAmb;\n uint16 public immutable destinationChainId;\n\n // Special Succinct event for additional tracking information.\n event SuccinctMessageRelayed(bytes32 messageRoot, uint16 destinationChainId, address target, bytes message);\n\n /**\n * @notice Constructs new Adapter.\n * @param _succinctSourceAmb address of the SourceAmb succinct contract for sending messages.\n * @param _destinationChainId chainId of the destination.\n */\n constructor(ITelepathyBroadcaster _succinctSourceAmb, uint16 _destinationChainId) {\n succinctSourceAmb = _succinctSourceAmb;\n destinationChainId = _destinationChainId;\n }\n\n /**\n * @notice Send cross-chain message to target on the destination.\n * @param target Contract on the destination that will receive the message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n bytes32 messageRoot = succinctSourceAmb.send(destinationChainId, target, message);\n\n // Note: this emits two events. MessageRelayed for the sake of compatibility with other adapters.\n // It emits SuccinctMessageRelayed to encode additional tracking information that is Succinct-specific.\n emit MessageRelayed(target, message);\n emit SuccinctMessageRelayed(messageRoot, destinationChainId, target, message);\n }\n\n /**\n * @notice No-op relay tokens method.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n // This method is intentionally left as a no-op.\n // If the adapter is intended to be able to relay tokens, this method should be overriden.\n }\n}\n" }, "contracts/external/interfaces/SuccinctInterfaces.sol": { "content": "pragma solidity ^0.8.0;\n\n// These interfaces are a subset of the Succinct interfaces here: https://github.com/succinctlabs/telepathy-contracts.\n\n// This interface should be implemented by any contract wanting to receive messages sent over the Succinct bridge.\ninterface ITelepathyHandler {\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external returns (bytes4);\n}\n\n// This interface represents the contract that we call into to send messages over the Succinct AMB.\ninterface ITelepathyBroadcaster {\n function send(\n uint16 _recipientChainId,\n address _recipientAddress,\n bytes calldata _data\n ) external returns (bytes32);\n}\n" }, "contracts/Succinct_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./external/interfaces/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n event SetSuccinctTargetAmb(address indexed newSuccinctTargetAmb);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be\n // misinterpreted. Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the adminCallValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure adminCallValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset adminCallValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n emit SetSuccinctTargetAmb(_succinctTargetAmb);\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(msg.sender == succinctTargetAmb, \"caller not succinct AMB\");\n require(_senderAddress == hubPool, \"sender not hubPool\");\n require(_sourceChainId == hubChainId, \"source chain not hub chain\");\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, _senderAddress);\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./external/interfaces/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n event SetSuccinctTargetAmb(address indexed newSuccinctTargetAmb);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be\n // misinterpreted. Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the adminCallValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure adminCallValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset adminCallValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n emit SetSuccinctTargetAmb(_succinctTargetAmb);\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(msg.sender == succinctTargetAmb, \"caller not succinct AMB\");\n require(_senderAddress == hubPool, \"sender not hubPool\");\n require(_sourceChainId == hubChainId, \"source chain not hub chain\");\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, _senderAddress);\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Send tokens to Polygon.\n */\ninterface IRootChainManager {\n /**\n * @notice Send msg.value of ETH to Polygon\n * @param user Recipient of ETH on Polygon.\n */\n function depositEtherFor(address user) external payable;\n\n /**\n * @notice Send ERC20 tokens to Polygon.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param rootToken L1 Address of token to send.\n * @param depositData Data to pass to L2 including amount of tokens to send. Should be abi.encode(amount).\n */\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\n/**\n * @notice Send arbitrary messages to Polygon.\n */\ninterface IFxStateSender {\n /**\n * @notice Send arbitrary message to Polygon.\n * @param _receiver Address on Polygon to receive message.\n * @param _data Message to send to `_receiver` on Polygon.\n */\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Similar to RootChainManager, but for Matic (Plasma) bridge.\n */\ninterface DepositManager {\n /**\n * @notice Send tokens to Polygon. Only used to send MATIC in this Polygon_Adapter.\n * @param token L1 token to send. Should be MATIC.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param amount Amount of `token` to send.\n */\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9Interface public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9Interface _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Send tokens to Polygon.\n */\ninterface IRootChainManager {\n /**\n * @notice Send msg.value of ETH to Polygon\n * @param user Recipient of ETH on Polygon.\n */\n function depositEtherFor(address user) external payable;\n\n /**\n * @notice Send ERC20 tokens to Polygon.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param rootToken L1 Address of token to send.\n * @param depositData Data to pass to L2 including amount of tokens to send. Should be abi.encode(amount).\n */\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\n/**\n * @notice Send arbitrary messages to Polygon.\n */\ninterface IFxStateSender {\n /**\n * @notice Send arbitrary message to Polygon.\n * @param _receiver Address on Polygon to receive message.\n * @param _data Message to send to `_receiver` on Polygon.\n */\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Similar to RootChainManager, but for Matic (Plasma) bridge.\n */\ninterface DepositManager {\n /**\n * @notice Send tokens to Polygon. Only used to send MATIC in this Polygon_Adapter.\n * @param token L1 token to send. Should be MATIC.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param amount Amount of `token` to send.\n */\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9Interface public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9Interface _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Synthetix custom bridge to Optimism.\n */\ninterface SynthetixBridgeToOptimism is IL1StandardBridge {\n /**\n * @notice Send tokens to Optimism.\n * @param to Address to send tokens to on L2.\n * @param amount Amount of tokens to send.\n */\n function depositTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore it's only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0x39Ea01a0298C315d149a490E34B59Dbf2EC7e48F;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n address bridgeToUse = address(l1StandardBridge);\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) bridgeToUse = daiOptimismBridge; // 1. DAI\n if (l1Token == snx) bridgeToUse = snxOptimismBridge; // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(bridgeToUse, amount);\n if (l1Token == snx) SynthetixBridgeToOptimism(bridgeToUse).depositTo(to, amount);\n else IL1StandardBridge(bridgeToUse).depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Synthetix custom bridge to Optimism.\n */\ninterface SynthetixBridgeToOptimism is IL1StandardBridge {\n /**\n * @notice Send tokens to Optimism.\n * @param to Address to send tokens to on L2.\n * @param amount Amount of tokens to send.\n */\n function depositTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore it's only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0x39Ea01a0298C315d149a490E34B59Dbf2EC7e48F;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n address bridgeToUse = address(l1StandardBridge);\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) bridgeToUse = daiOptimismBridge; // 1. DAI\n if (l1Token == snx) bridgeToUse = snxOptimismBridge; // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(bridgeToUse, amount);\n if (l1Token == snx) SynthetixBridgeToOptimism(bridgeToUse).depositTo(to, amount);\n else IL1StandardBridge(bridgeToUse).depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -233,28 +233,28 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Arbitrum's L1 Inbox contract used to send messages to Arbitrum.\n */\ninterface ArbitrumL1InboxLike {\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @dev Caller must set msg.value equal to at least `maxSubmissionCost + maxGas * gasPriceBid`.\n * all msg.value will deposited to callValueRefundAddress on L2\n * @dev More details can be found here: https://developer.arbitrum.io/arbos/l1-to-l2-messaging\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function createRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed\n * funds come from the deposit alone, rather than falling back on the user's L2 balance\n * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).\n * createRetryableTicket method is the recommended standard.\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function unsafeCreateRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\n/**\n * @notice Layer 1 Gateway contract for bridging standard ERC20s to Arbitrum.\n */\ninterface ArbitrumL1ERC20GatewayLike {\n /**\n * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges\n * like the DAI bridge.\n * @dev Refunded to aliased L2 address of sender if sender has code on L1, otherwise to to sender's EOA on L2.\n * @param _l1Token L1 address of ERC20\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice Deposit ERC20 token from Ethereum into Arbitrum.\n * @dev L2 address alias will not be applied to the following types of addresses on L1:\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * @param _l1Token L1 address of ERC20\n * @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransferCustomRefund(\n address _l1Token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice get ERC20 gateway for token.\n * @param _token ERC20 address.\n * @return address of ERC20 gateway.\n */\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Arbitrum's L1 Inbox contract used to send messages to Arbitrum.\n */\ninterface ArbitrumL1InboxLike {\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @dev Caller must set msg.value equal to at least `maxSubmissionCost + maxGas * gasPriceBid`.\n * all msg.value will deposited to callValueRefundAddress on L2\n * @dev More details can be found here: https://developer.arbitrum.io/arbos/l1-to-l2-messaging\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function createRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed\n * funds come from the deposit alone, rather than falling back on the user's L2 balance\n * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).\n * createRetryableTicket method is the recommended standard.\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function unsafeCreateRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\n/**\n * @notice Layer 1 Gateway contract for bridging standard ERC20s to Arbitrum.\n */\ninterface ArbitrumL1ERC20GatewayLike {\n /**\n * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges\n * like the DAI bridge.\n * @dev Refunded to aliased L2 address of sender if sender has code on L1, otherwise to to sender's EOA on L2.\n * @param _l1Token L1 address of ERC20\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice Deposit ERC20 token from Ethereum into Arbitrum.\n * @dev L2 address alias will not be applied to the following types of addresses on L1:\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * @param _l1Token L1 address of ERC20\n * @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransferCustomRefund(\n address _l1Token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice get ERC20 gateway for token.\n * @param _token ERC20 address.\n * @return address of ERC20 gateway.\n */\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.unsafeCreateRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.unsafeCreateRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n// https://github.com/Synthetixio/synthetix/blob/5ca27785fad8237fb0710eac01421cafbbd69647/contracts/SynthetixBridgeToBase.sol#L50\ninterface SynthetixBridgeToBase {\n function withdrawTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas;\n\n // ETH is an ERC20 on OVM.\n address public l2Eth;\n\n // Address of the Optimism L2 messenger.\n address public messenger;\n\n // Address of custom bridge used to bridge Synthetix-related assets like SNX.\n address private constant SYNTHETIX_BRIDGE = 0x136b1EC699c62b0606854056f02dC7Bb80482d63;\n\n // Address of SNX ERC20\n address private constant SNX = 0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n */\n function __OvmSpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken\n ) public onlyInitializing {\n l1Gas = 5_000_000;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER;\n //slither-disable-next-line missing-zero-check\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n //slither-disable-next-line arbitrary-send-eth\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9Interface(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n // Handle custom SNX bridge which doesn't conform to the standard bridge interface.\n if (relayerRefundLeaf.l2TokenAddress == SNX)\n SynthetixBridgeToBase(SYNTHETIX_BRIDGE).withdrawTo(\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn // _amount.\n );\n else\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal view override {\n require(\n LibOptimismUpgradeable.crossChainSender(messenger) == crossDomainAdmin,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n// https://github.com/Synthetixio/synthetix/blob/5ca27785fad8237fb0710eac01421cafbbd69647/contracts/SynthetixBridgeToBase.sol#L50\ninterface SynthetixBridgeToBase {\n function withdrawTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas;\n\n // ETH is an ERC20 on OVM.\n address public l2Eth;\n\n // Address of the Optimism L2 messenger.\n address public messenger;\n\n // Address of custom bridge used to bridge Synthetix-related assets like SNX.\n address private constant SYNTHETIX_BRIDGE = 0x136b1EC699c62b0606854056f02dC7Bb80482d63;\n\n // Address of SNX ERC20\n address private constant SNX = 0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n */\n function __OvmSpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken\n ) public onlyInitializing {\n l1Gas = 5_000_000;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER;\n //slither-disable-next-line missing-zero-check\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n //slither-disable-next-line arbitrary-send-eth\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9Interface(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n // Handle custom SNX bridge which doesn't conform to the standard bridge interface.\n if (relayerRefundLeaf.l2TokenAddress == SNX)\n SynthetixBridgeToBase(SYNTHETIX_BRIDGE).withdrawTo(\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn // _amount.\n );\n else\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal view override {\n require(\n LibOptimismUpgradeable.crossChainSender(messenger) == crossDomainAdmin,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/LibOptimism.sol)\n\npragma solidity ^0.8.4;\n\nimport { ICrossDomainMessengerUpgradeable as Optimism_Bridge } from \"../../vendor/optimism/ICrossDomainMessengerUpgradeable.sol\";\nimport \"../errorsUpgradeable.sol\";\n\n/**\n * @dev Primitives for cross-chain aware contracts for https://www.optimism.io/[Optimism].\n * See the https://community.optimism.io/docs/developers/bridge/messaging/#accessing-msg-sender[documentation]\n * for the functionality used here.\n */\nlibrary LibOptimismUpgradeable {\n /**\n * @dev Returns whether the current function call is the result of a\n * cross-chain message relayed by `messenger`.\n */\n function isCrossChain(address messenger) internal view returns (bool) {\n return msg.sender == messenger;\n }\n\n /**\n * @dev Returns the address of the sender that triggered the current\n * cross-chain message through `messenger`.\n *\n * NOTE: {isCrossChain} should be checked before trying to recover the\n * sender, as it will revert with `NotCrossChainCall` if the current\n * function call is not the result of a cross-chain message.\n */\n function crossChainSender(address messenger) internal view returns (address) {\n if (!isCrossChain(messenger)) revert NotCrossChainCall();\n\n return Optimism_Bridge(messenger).xDomainMessageSender();\n }\n}\n" @@ -272,31 +272,31 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (vendor/optimism/ICrossDomainMessenger.sol)\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessengerUpgradeable {\n /**********\n * Events *\n **********/\n\n event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit);\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/test/AcrossMessageHandlerMock.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\n\ncontract AcrossMessageHandlerMock is AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external override {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\n\ncontract AcrossMessageHandlerMock is AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external override {}\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n //slither-disable-next-line unused-return\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n //slither-disable-next-line unused-return\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -305,28 +305,28 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "contracts/test/ArbitrumMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ncontract ArbitrumMockErc20GatewayRouter {\n function outboundTransferCustomRefund(\n address,\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function outboundTransfer(\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function getGateway(address) external view returns (address) {\n return address(this);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ncontract ArbitrumMockErc20GatewayRouter {\n function outboundTransferCustomRefund(\n address,\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function outboundTransfer(\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function getGateway(address) external view returns (address) {\n return address(this);\n }\n}\n" }, "contracts/test/SuccinctMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ncontract TelepathyBroadcasterMock {\n function send(\n uint16,\n address,\n bytes calldata\n ) external pure returns (bytes32) {\n return bytes32(0);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ncontract TelepathyBroadcasterMock {\n function send(\n uint16,\n address,\n bytes calldata\n ) external pure returns (bytes32) {\n return bytes32(0);\n }\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json b/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json index 633034a1..e20202ac 100644 --- a/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json +++ b/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/merkle-distributor/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is Ownable {\n using SafeERC20 for IERC20;\n\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) external {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n merkleWindows[_claim.windowIndex].remainingAmount -= batchedAmount;\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) external {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is Ownable {\n using SafeERC20 for IERC20;\n\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) external {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n merkleWindows[_claim.windowIndex].remainingAmount -= batchedAmount;\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) external {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,73 +32,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -113,13 +113,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -128,58 +128,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -188,22 +188,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/kovan/AcrossConfigStore.json b/deployments/kovan/AcrossConfigStore.json index 3d105e8e..a2ba3695 100644 --- a/deployments/kovan/AcrossConfigStore.json +++ b/deployments/kovan/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f838061007e6000396000f3fe60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Ethereum_Adapter.json b/deployments/kovan/Ethereum_Adapter.json index 2347ba83..5c0305db 100644 --- a/deployments/kovan/Ethereum_Adapter.json +++ b/deployments/kovan/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Ethereum_SpokePool.json b/deployments/kovan/Ethereum_SpokePool.json index 9b35e1e5..7565d55b 100644 --- a/deployments/kovan/Ethereum_SpokePool.json +++ b/deployments/kovan/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200466b3803806200466b8339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b608051614382620002e9600039600081816101d901528181610ce601528181610daf0152818161234d01528181612bd30152612c2901526143826000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/LpTokenFactory.json b/deployments/kovan/LpTokenFactory.json index 3e71a0aa..cb3685b8 100644 --- a/deployments/kovan/LpTokenFactory.json +++ b/deployments/kovan/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Optimism_Adapter.json b/deployments/kovan/Optimism_Adapter.json index 428bab46..9bc90b13 100644 --- a/deployments/kovan/Optimism_Adapter.json +++ b/deployments/kovan/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052621e848060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161113538038061113583398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f606101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108ca0152610f606000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index 2a6425e5..a0cc1d52 100644 --- a/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json b/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json index 08c3cc5c..52e7ecd2 100644 --- a/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json +++ b/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/mainnet/AcrossConfigStore.json b/deployments/mainnet/AcrossConfigStore.json index 8d3dd3ad..451c31c5 100644 --- a/deployments/mainnet/AcrossConfigStore.json +++ b/deployments/mainnet/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f838061007e6000396000f3fe60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_Adapter.json b/deployments/mainnet/Arbitrum_Adapter.json index 7e0a3f8b..681870f0 100644 --- a/deployments/mainnet/Arbitrum_Adapter.json +++ b/deployments/mainnet/Arbitrum_Adapter.json @@ -243,7 +243,7 @@ "args": ["0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef"], "numDeployments": 1, "solcInputHash": "aa94850b4a0bee17111a41299cfa0033", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_MESSAGE_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"l2GasLimit\",\"type\":\"uint32\"}],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue(uint32)\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue(uint32)\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x09fa3131b8c17515dc85595521fc23524b1c5897a494ae33c4a30b525bf0e4fe\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_MESSAGE_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"l2GasLimit\",\"type\":\"uint32\"}],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue(uint32)\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue(uint32)\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x09fa3131b8c17515dc85595521fc23524b1c5897a494ae33c4a30b525bf0e4fe\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405234801561001057600080fd5b5060405161128338038061128383398101604081905261002f9161005e565b6001600160a01b039182166080521660a052610098565b6001600160a01b038116811461005b57600080fd5b50565b6000806040838503121561007157600080fd5b825161007c81610046565b602084015190925061008d81610046565b809150509250929050565b60805160a0516111ab6100d86000396000818160c8015281816102c40152818161041b015261050c015260008181610195015261064c01526111ab6000f3fe6080604052600436106100b15760003560e01c80639ae3668511610069578063c735281e1161004e578063c735281e146101f8578063e599477e1461020f578063e6eb8ade1461022a57600080fd5b80639ae36685146101b75780639c3ba200146101d057600080fd5b806328f2716e1161009a57806328f2716e1461014257806352c8c75c1461016e5780638134f3851461018357600080fd5b80631ba4a9cb146100b65780631fc1ba7614610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610c27565b61023d565b60405190815260200161010b565b34801561014e57600080fd5b50610159620493e081565b60405163ffffffff909116815260200161010b565b61018161017c366004610c72565b61026b565b005b34801561018f57600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061013464012a05f20081565b3480156101dc57600080fd5b506100ea73428ab2ba90eba0a4be7af34c9ac451ab061ac01081565b34801561020457600080fd5b50610159621e848081565b34801561021b57600080fd5b50610134662386f26fc1000081565b610181610238366004610d89565b61063a565b600061025463ffffffff831664012a05f200610e4b565b61026590662386f26fc10000610e88565b92915050565b6000610279620493e0610758565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561030b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032f9190610ea0565b905061035273ffffffffffffffffffffffffffffffffffffffff871682866107d9565b6000662386f26fc1000060405160200161037d91815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905073ffffffffffffffffffffffffffffffffffffffff8716736b175474e89094c44da98b954eedeac495271d0f036104cf576040517fd2ce7d6500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d65908590610464908b9089908b90620493e09064012a05f200908a90600401610f33565b60006040518083038185885af1158015610482573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c99190810190610f90565b506105d2565b6040517f4fb1a07b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634fb1a07b90859061056b908b9073428ab2ba90eba0a4be7af34c9ac451ab061ac010908a908c90620493e09064012a05f200908b90600401611007565b60006040518083038185885af1158015610589573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105d09190810190610f90565b505b6040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b6000610648621e8480610758565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded82856000662386f26fc1000073428ab2ba90eba0a4be7af34c9ac451ab061ac01080621e848064012a05f2008b6040518a63ffffffff1660e01b81526004016106d698979695949392919061106d565b60206040518083038185885af11580156106f4573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061071991906110dc565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4838360405161074b9291906110f5565b60405180910390a1505050565b60006107638261023d565b9050804710156107d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b919050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087491906110dc565b61087e9190610e88565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090e908590610914565b50505050565b6000610976826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a259092919063ffffffff16565b805190915015610a2057808060200190518101906109949190611124565b610a20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107cb565b505050565b6060610a348484600085610a3e565b90505b9392505050565b606082471015610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107cb565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b779190611146565b60006040518083038185875af1925050503d8060008114610bb4576040519150601f19603f3d011682016040523d82523d6000602084013e610bb9565b606091505b5091509150610bc9828286610bd4565b979650505050505050565b60608315610be3575081610a37565b825115610bf35782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107cb9190611162565b600060208284031215610c3957600080fd5b813563ffffffff81168114610a3757600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c6f57600080fd5b50565b60008060008060808587031215610c8857600080fd5b8435610c9381610c4d565b93506020850135610ca381610c4d565b9250604085013591506060850135610cba81610c4d565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3b57610d3b610cc5565b604052919050565b600067ffffffffffffffff821115610d5d57610d5d610cc5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d9c57600080fd5b8235610da781610c4d565b9150602083013567ffffffffffffffff811115610dc357600080fd5b8301601f81018513610dd457600080fd5b8035610de7610de282610d43565b610cf4565b818152866020838501011115610dfc57600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e8357610e83610e1c565b500290565b60008219821115610e9b57610e9b610e1c565b500190565b600060208284031215610eb257600080fd5b8151610a3781610c4d565b60005b83811015610ed8578181015183820152602001610ec0565b8381111561090e5750506000910152565b60008151808452610f01816020860160208601610ebd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f8460c0830184610ee9565b98975050505050505050565b600060208284031215610fa257600080fd5b815167ffffffffffffffff811115610fb957600080fd5b8201601f81018413610fca57600080fd5b8051610fd8610de282610d43565b818152856020838501011115610fed57600080fd5b610ffe826020830160208601610ebd565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff851660808301528360a083015260e060c083015261106060e0830184610ee9565b9998505050505050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e08401526110cd81840185610ee9565b9b9a5050505050505050505050565b6000602082840312156110ee57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a346040830184610ee9565b60006020828403121561113657600080fd5b81518015158114610a3757600080fd5b60008251611158818460208701610ebd565b9190910192915050565b602081526000610a376020830184610ee956fea2646970667358221220b1f5489e25d9caa366e02e9f1600d99235c2ecffa1dee5130a86e9d1a2b8130064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c80639ae3668511610069578063c735281e1161004e578063c735281e146101f8578063e599477e1461020f578063e6eb8ade1461022a57600080fd5b80639ae36685146101b75780639c3ba200146101d057600080fd5b806328f2716e1161009a57806328f2716e1461014257806352c8c75c1461016e5780638134f3851461018357600080fd5b80631ba4a9cb146100b65780631fc1ba7614610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610c27565b61023d565b60405190815260200161010b565b34801561014e57600080fd5b50610159620493e081565b60405163ffffffff909116815260200161010b565b61018161017c366004610c72565b61026b565b005b34801561018f57600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061013464012a05f20081565b3480156101dc57600080fd5b506100ea73428ab2ba90eba0a4be7af34c9ac451ab061ac01081565b34801561020457600080fd5b50610159621e848081565b34801561021b57600080fd5b50610134662386f26fc1000081565b610181610238366004610d89565b61063a565b600061025463ffffffff831664012a05f200610e4b565b61026590662386f26fc10000610e88565b92915050565b6000610279620493e0610758565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561030b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032f9190610ea0565b905061035273ffffffffffffffffffffffffffffffffffffffff871682866107d9565b6000662386f26fc1000060405160200161037d91815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905073ffffffffffffffffffffffffffffffffffffffff8716736b175474e89094c44da98b954eedeac495271d0f036104cf576040517fd2ce7d6500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d65908590610464908b9089908b90620493e09064012a05f200908a90600401610f33565b60006040518083038185885af1158015610482573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c99190810190610f90565b506105d2565b6040517f4fb1a07b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634fb1a07b90859061056b908b9073428ab2ba90eba0a4be7af34c9ac451ab061ac010908a908c90620493e09064012a05f200908b90600401611007565b60006040518083038185885af1158015610589573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105d09190810190610f90565b505b6040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b6000610648621e8480610758565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded82856000662386f26fc1000073428ab2ba90eba0a4be7af34c9ac451ab061ac01080621e848064012a05f2008b6040518a63ffffffff1660e01b81526004016106d698979695949392919061106d565b60206040518083038185885af11580156106f4573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061071991906110dc565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4838360405161074b9291906110f5565b60405180910390a1505050565b60006107638261023d565b9050804710156107d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b919050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087491906110dc565b61087e9190610e88565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090e908590610914565b50505050565b6000610976826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a259092919063ffffffff16565b805190915015610a2057808060200190518101906109949190611124565b610a20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107cb565b505050565b6060610a348484600085610a3e565b90505b9392505050565b606082471015610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107cb565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b779190611146565b60006040518083038185875af1925050503d8060008114610bb4576040519150601f19603f3d011682016040523d82523d6000602084013e610bb9565b606091505b5091509150610bc9828286610bd4565b979650505050505050565b60608315610be3575081610a37565b825115610bf35782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107cb9190611162565b600060208284031215610c3957600080fd5b813563ffffffff81168114610a3757600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c6f57600080fd5b50565b60008060008060808587031215610c8857600080fd5b8435610c9381610c4d565b93506020850135610ca381610c4d565b9250604085013591506060850135610cba81610c4d565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3b57610d3b610cc5565b604052919050565b600067ffffffffffffffff821115610d5d57610d5d610cc5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d9c57600080fd5b8235610da781610c4d565b9150602083013567ffffffffffffffff811115610dc357600080fd5b8301601f81018513610dd457600080fd5b8035610de7610de282610d43565b610cf4565b818152866020838501011115610dfc57600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e8357610e83610e1c565b500290565b60008219821115610e9b57610e9b610e1c565b500190565b600060208284031215610eb257600080fd5b8151610a3781610c4d565b60005b83811015610ed8578181015183820152602001610ec0565b8381111561090e5750506000910152565b60008151808452610f01816020860160208601610ebd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f8460c0830184610ee9565b98975050505050505050565b600060208284031215610fa257600080fd5b815167ffffffffffffffff811115610fb957600080fd5b8201601f81018413610fca57600080fd5b8051610fd8610de282610d43565b818152856020838501011115610fed57600080fd5b610ffe826020830160208601610ebd565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff851660808301528360a083015260e060c083015261106060e0830184610ee9565b9998505050505050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e08401526110cd81840185610ee9565b9b9a5050505050505050505050565b6000602082840312156110ee57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a346040830184610ee9565b60006020828403121561113657600080fd5b81518015158114610a3757600080fd5b60008251611158818460208701610ebd565b9190910192915050565b602081526000610a376020830184610ee956fea2646970667358221220b1f5489e25d9caa366e02e9f1600d99235c2ecffa1dee5130a86e9d1a2b8130064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_RescueAdapter.json b/deployments/mainnet/Arbitrum_RescueAdapter.json index de2de3b5..fc1b3214 100644 --- a/deployments/mainnet/Arbitrum_RescueAdapter.json +++ b/deployments/mainnet/Arbitrum_RescueAdapter.json @@ -219,7 +219,7 @@ "args": ["0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f"], "numDeployments": 1, "solcInputHash": "9ecc79ca0809d14763bad8554b06546b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"aliasedL2HubPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to aliased hub pool.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to aliased hub pool address on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send transactions as if called by the aliased HubPool address.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":\"Arbitrum_RescueAdapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n function createRetryableTicketNoRefundAliasRewrite(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1273df00da12b4eb144cbfd15b32a2353a46cfd66f3440074f782a17084bf53d\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"./Arbitrum_Adapter.sol\\\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\\n * transactions as if called by the aliased HubPool address.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_RescueAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\\n l1Inbox = _l1ArbitrumInbox;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param message Data to send to aliased hub pool.\\n */\\n function relayMessage(address, bytes memory message) external payable override {\\n uint256 valueToReturn = abi.decode(message, (uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\\n l2RefundL2Address, // destAddr destination L2 contract address\\n valueToReturn, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n \\\"\\\" // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(aliasedL2HubPoolAddress, \\\"\\\");\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"useless function\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x28e520a2456ac047fca4e21aed8d0ce0a4d731941922a83ab56ec12543681f19\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"aliasedL2HubPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to aliased hub pool.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to aliased hub pool address on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send transactions as if called by the aliased HubPool address.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":\"Arbitrum_RescueAdapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n function createRetryableTicketNoRefundAliasRewrite(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1273df00da12b4eb144cbfd15b32a2353a46cfd66f3440074f782a17084bf53d\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"./Arbitrum_Adapter.sol\\\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\\n * transactions as if called by the aliased HubPool address.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_RescueAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\\n l1Inbox = _l1ArbitrumInbox;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param message Data to send to aliased hub pool.\\n */\\n function relayMessage(address, bytes memory message) external payable override {\\n uint256 valueToReturn = abi.decode(message, (uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\\n l2RefundL2Address, // destAddr destination L2 contract address\\n valueToReturn, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n \\\"\\\" // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(aliasedL2HubPoolAddress, \\\"\\\");\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"useless function\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x28e520a2456ac047fca4e21aed8d0ce0a4d731941922a83ab56ec12543681f19\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052662386f26fc1000060805264012a05f20060a052621e848060c05273d297fa914353c44b2e33ebe05f21846f1048cfeb6101005234801561004557600080fd5b506040516109633803806109638339810160408190526100649161007a565b6001600160a01b0316610120523360e0526100aa565b60006020828403121561008c57600080fd5b81516001600160a01b03811681146100a357600080fd5b9392505050565b60805160a05160c05160e051610100516101205161082c61013760003960008181610143015261046c01526000818160d501526104e50152600081816101ab01526103a40152600081816101df0152818161026901526104070152600081816101770152818161028b0152610433015260008181610228015281816102b501526103d5015261082c6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631cf3ec03146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a3660046105fd565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610679565b610345565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610788565b6102d9907f00000000000000000000000000000000000000000000000000000000000000006107c5565b905090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f7573656c6573732066756e6374696f6e0000000000000000000000000000000060448201526064015b60405180910390fd5b60008180602001905181019061035b91906107dd565b9050600061036761055b565b6040517f1b871c8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301819052602483018690527f000000000000000000000000000000000000000000000000000000000000000060448401526064830181905260848301527f000000000000000000000000000000000000000000000000000000000000000063ffffffff1660a48301527f000000000000000000000000000000000000000000000000000000000000000060c483015261010060e483015260006101048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631b871c8d9083906101240160206040518083038185885af11580156104b9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104de91906107dd565b50604080517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020810182905260008183015290517f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac49181900360600190a150505050565b600061056561025d565b9050804710156105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e63650000000000000000604482015260640161033c565b90565b803573ffffffffffffffffffffffffffffffffffffffff811681146105f857600080fd5b919050565b6000806000806080858703121561061357600080fd5b61061c856105d4565b935061062a602086016105d4565b92506040850135915061063f606086016105d4565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561068c57600080fd5b610695836105d4565b9150602083013567ffffffffffffffff808211156106b257600080fd5b818501915085601f8301126106c657600080fd5b8135818111156106d8576106d861064a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071e5761071e61064a565b8160405282815288602084870101111561073757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156107c0576107c0610759565b500290565b600082198211156107d8576107d8610759565b500190565b6000602082840312156107ef57600080fd5b505191905056fea2646970667358221220d8698f702b3480c3be52c8e3f34a23d2bb2883baed6d88c84ca110c226d46c4464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631cf3ec03146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a3660046105fd565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610679565b610345565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610788565b6102d9907f00000000000000000000000000000000000000000000000000000000000000006107c5565b905090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f7573656c6573732066756e6374696f6e0000000000000000000000000000000060448201526064015b60405180910390fd5b60008180602001905181019061035b91906107dd565b9050600061036761055b565b6040517f1b871c8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301819052602483018690527f000000000000000000000000000000000000000000000000000000000000000060448401526064830181905260848301527f000000000000000000000000000000000000000000000000000000000000000063ffffffff1660a48301527f000000000000000000000000000000000000000000000000000000000000000060c483015261010060e483015260006101048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631b871c8d9083906101240160206040518083038185885af11580156104b9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104de91906107dd565b50604080517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020810182905260008183015290517f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac49181900360600190a150505050565b600061056561025d565b9050804710156105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e63650000000000000000604482015260640161033c565b90565b803573ffffffffffffffffffffffffffffffffffffffff811681146105f857600080fd5b919050565b6000806000806080858703121561061357600080fd5b61061c856105d4565b935061062a602086016105d4565b92506040850135915061063f606086016105d4565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561068c57600080fd5b610695836105d4565b9150602083013567ffffffffffffffff808211156106b257600080fd5b818501915085601f8301126106c657600080fd5b8135818111156106d8576106d861064a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071e5761071e61064a565b8160405282815288602084870101111561073757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156107c0576107c0610759565b500290565b600082198211156107d8576107d8610759565b500190565b6000602082840312156107ef57600080fd5b505191905056fea2646970667358221220d8698f702b3480c3be52c8e3f34a23d2bb2883baed6d88c84ca110c226d46c4464736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_SendTokensAdapter.json b/deployments/mainnet/Arbitrum_SendTokensAdapter.json index 025f4828..6901af75 100644 --- a/deployments/mainnet/Arbitrum_SendTokensAdapter.json +++ b/deployments/mainnet/Arbitrum_SendTokensAdapter.json @@ -206,7 +206,7 @@ "args": ["0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef"], "numDeployments": 1, "solcInputHash": "778ed9956c3f76e793496228f16e1373", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"details\":\"This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens the Arbitrum_SpokePool out of the HubPool.\",\"params\":{\"message\":\"The encoded address of the ERC20 to send to the rescue address.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger this function.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool received a duplicate root bundle relay, due to some replay issue.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":\"Arbitrum_SendTokensAdapter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n\\n function unsafeCreateRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xf01d3a899cdeec331b26bbe416cb22f500142002d3ad4c182e01cd44c17d5d11\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport { ArbitrumL1ERC20GatewayLike } from \\\"./Arbitrum_Adapter.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\\n * received a duplicate root bundle relay, due to some replay issue.\\n */\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n uint256 public immutable l2GasPrice = 5e9;\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\\n * this function.\\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\\n * the Arbitrum_SpokePool out of the HubPool.\\n * @param message The encoded address of the ERC20 to send to the rescue address.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n target,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n\\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\\n // emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"relayTokens disabled\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45bafc3f5136bc882620977850a7c4a1d0ee65d69fb65eb165496714e91f536f\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"details\":\"This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens the Arbitrum_SpokePool out of the HubPool.\",\"params\":{\"message\":\"The encoded address of the ERC20 to send to the rescue address.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger this function.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool received a duplicate root bundle relay, due to some replay issue.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":\"Arbitrum_SendTokensAdapter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n\\n function unsafeCreateRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xf01d3a899cdeec331b26bbe416cb22f500142002d3ad4c182e01cd44c17d5d11\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport { ArbitrumL1ERC20GatewayLike } from \\\"./Arbitrum_Adapter.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\\n * received a duplicate root bundle relay, due to some replay issue.\\n */\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n uint256 public immutable l2GasPrice = 5e9;\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\\n * this function.\\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\\n * the Arbitrum_SpokePool out of the HubPool.\\n * @param message The encoded address of the ERC20 to send to the rescue address.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n target,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n\\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\\n // emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"relayTokens disabled\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45bafc3f5136bc882620977850a7c4a1d0ee65d69fb65eb165496714e91f536f\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60e0346100b357601f610c6738819003918201601f19168301916001600160401b038311848410176100b8578084926020946040528339810103126100b357516001600160a01b03811681036100b357662386f26fc1000060805264012a05f20060a05260c052604051610b9890816100cf82396080518181816102f9015281816106a00152610b3b015260a05181818161037a015281816107440152610b06015260c05181818161015001526108ad0152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe6040608081526004908136101561001557600080fd5b600090813560e01c806308f1ed15146108d15780631ba4a9cb1461086357806328f2716e1461082857806352c8c75c146107675780639ae366851461070f5780639c3ba200146106c3578063e599477e1461066b5763e6eb8ade1461007957600080fd5b807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576100aa610912565b9260249081359167ffffffffffffffff9182841161043057366023850112156104305783810135936100db856109c6565b906100e887519283610985565b858252602095868301913686838301011161066357818a92878a9301853784010152868280518101031261065f57519173ffffffffffffffffffffffffffffffffffffffff9182841680940361065b57870151610143610b00565b92834710610600578086917f0000000000000000000000000000000000000000000000000000000000000000169b898d8c51948580927fbda009fe0000000000000000000000000000000000000000000000000000000082528b8a8301525afa9283156105f6578c936105ba575b50818b51937fdd62ed3e00000000000000000000000000000000000000000000000000000000855230878601521680898501526044938b8186818c5afa80156105ae5786908f90610579575b6102079250610a66565b908c51918c8301917f095ea7b30000000000000000000000000000000000000000000000000000000083528b840152858301528482526102468261093a565b8c51918d83018381108d82111761054d578e528c83527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648d840152893b156104f2578e8e818f938d6102c4979683809351925af1913d156104e6573d6102b76102ae826109c6565b93519384610985565b825281933d92013e610aa2565b80518061043e575b50508b9c95938b9c989795936103af938c938e73428ab2ba90eba0a4be7af34c9ac451ab061ac0109f51957f00000000000000000000000000000000000000000000000000000000000000009087015280808701528c6060870152606086526103348661093a565b519e8f9b8c9a8b997f4fb1a07b000000000000000000000000000000000000000000000000000000008b528a015288015216908501526064840152620493e060848401527f000000000000000000000000000000000000000000000000000000000000000060a484015260e060c484015260e4830190610a23565b03925af18015610434576103c1578480f35b3d8086853e6103d08185610985565b830192828185031261043057805191821161043057019082601f8301121561042c5781519261040a610401856109c6565b95519586610985565b83855281848401011161042c578061042494019101610a00565b388080808480f35b8480fd5b8580fd5b84513d87823e3d90fd5b818c91810103126104e2578a01518015908115036104e2576104615738806102cc565b6084857f5361666545524332303a204552433230206f7065726174696f6e20646964206e85602a8f8f8e9151957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8c80fd5b50509050606090610aa2565b8d517f08c379a00000000000000000000000000000000000000000000000000000000081528089018e9052601d818d01527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081880152606490fd5b508a8f60418a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50508b81813d83116105a7575b6105908183610985565b810103126105a3578561020791516101fd565b8d80fd5b503d610586565b8e8e51903d90823e3d90fd5b9092508981813d83116105ef575b6105d28183610985565b810103126105eb575181811681036105eb5791386101b1565b8b80fd5b503d6105c8565b8b513d8e823e3d90fd5b6064836018888b8d51937f08c379a00000000000000000000000000000000000000000000000000000000085528401528201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152fd5b8880fd5b8780fd5b8980fd5b5080fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173428ab2ba90eba0a4be7af34c9ac451ab061ac0108152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50919060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108255761079c610912565b5073ffffffffffffffffffffffffffffffffffffffff6024358181160361066757606435908116036108255750602060649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601460248201527f72656c6179546f6b656e732064697361626c65640000000000000000000000006044820152fd5b80fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209051620493e08152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209061090b610b00565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361093557565b600080fd5b6080810190811067ffffffffffffffff82111761095657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761095657604052565b67ffffffffffffffff811161095657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110610a135750506000910152565b8181015183820152602001610a03565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610a5f81518092818752878088019101610a00565b0116010190565b91908201809211610a7357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90919015610aae575090565b815115610abe5750805190602001fd5b610afc906040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352602060048401526024830190610a23565b0390fd5b620493e07f0000000000000000000000000000000000000000000000000000000000000000818102918115918304141715610a7357610b5f907f0000000000000000000000000000000000000000000000000000000000000000610a66565b9056fea26469706673582212204720938d7cb043f3ec85ed4a591ecd87e9eda6b87236ec70d1fbafbb1b476c2f64736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600090813560e01c806308f1ed15146108d15780631ba4a9cb1461086357806328f2716e1461082857806352c8c75c146107675780639ae366851461070f5780639c3ba200146106c3578063e599477e1461066b5763e6eb8ade1461007957600080fd5b807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576100aa610912565b9260249081359167ffffffffffffffff9182841161043057366023850112156104305783810135936100db856109c6565b906100e887519283610985565b858252602095868301913686838301011161066357818a92878a9301853784010152868280518101031261065f57519173ffffffffffffffffffffffffffffffffffffffff9182841680940361065b57870151610143610b00565b92834710610600578086917f0000000000000000000000000000000000000000000000000000000000000000169b898d8c51948580927fbda009fe0000000000000000000000000000000000000000000000000000000082528b8a8301525afa9283156105f6578c936105ba575b50818b51937fdd62ed3e00000000000000000000000000000000000000000000000000000000855230878601521680898501526044938b8186818c5afa80156105ae5786908f90610579575b6102079250610a66565b908c51918c8301917f095ea7b30000000000000000000000000000000000000000000000000000000083528b840152858301528482526102468261093a565b8c51918d83018381108d82111761054d578e528c83527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648d840152893b156104f2578e8e818f938d6102c4979683809351925af1913d156104e6573d6102b76102ae826109c6565b93519384610985565b825281933d92013e610aa2565b80518061043e575b50508b9c95938b9c989795936103af938c938e73428ab2ba90eba0a4be7af34c9ac451ab061ac0109f51957f00000000000000000000000000000000000000000000000000000000000000009087015280808701528c6060870152606086526103348661093a565b519e8f9b8c9a8b997f4fb1a07b000000000000000000000000000000000000000000000000000000008b528a015288015216908501526064840152620493e060848401527f000000000000000000000000000000000000000000000000000000000000000060a484015260e060c484015260e4830190610a23565b03925af18015610434576103c1578480f35b3d8086853e6103d08185610985565b830192828185031261043057805191821161043057019082601f8301121561042c5781519261040a610401856109c6565b95519586610985565b83855281848401011161042c578061042494019101610a00565b388080808480f35b8480fd5b8580fd5b84513d87823e3d90fd5b818c91810103126104e2578a01518015908115036104e2576104615738806102cc565b6084857f5361666545524332303a204552433230206f7065726174696f6e20646964206e85602a8f8f8e9151957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8c80fd5b50509050606090610aa2565b8d517f08c379a00000000000000000000000000000000000000000000000000000000081528089018e9052601d818d01527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081880152606490fd5b508a8f60418a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50508b81813d83116105a7575b6105908183610985565b810103126105a3578561020791516101fd565b8d80fd5b503d610586565b8e8e51903d90823e3d90fd5b9092508981813d83116105ef575b6105d28183610985565b810103126105eb575181811681036105eb5791386101b1565b8b80fd5b503d6105c8565b8b513d8e823e3d90fd5b6064836018888b8d51937f08c379a00000000000000000000000000000000000000000000000000000000085528401528201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152fd5b8880fd5b8780fd5b8980fd5b5080fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173428ab2ba90eba0a4be7af34c9ac451ab061ac0108152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50919060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108255761079c610912565b5073ffffffffffffffffffffffffffffffffffffffff6024358181160361066757606435908116036108255750602060649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601460248201527f72656c6179546f6b656e732064697361626c65640000000000000000000000006044820152fd5b80fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209051620493e08152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209061090b610b00565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361093557565b600080fd5b6080810190811067ffffffffffffffff82111761095657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761095657604052565b67ffffffffffffffff811161095657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110610a135750506000910152565b8181015183820152602001610a03565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610a5f81518092818752878088019101610a00565b0116010190565b91908201809211610a7357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90919015610aae575090565b815115610abe5750805190602001fd5b610afc906040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352602060048401526024830190610a23565b0390fd5b620493e07f0000000000000000000000000000000000000000000000000000000000000000818102918115918304141715610a7357610b5f907f0000000000000000000000000000000000000000000000000000000000000000610a66565b9056fea26469706673582212204720938d7cb043f3ec85ed4a591ecd87e9eda6b87236ec70d1fbafbb1b476c2f64736f6c63430008120033", "devdoc": { diff --git a/deployments/mainnet/Boba_Adapter.json b/deployments/mainnet/Boba_Adapter.json index 5bcea16a..c0c9e53e 100644 --- a/deployments/mainnet/Boba_Adapter.json +++ b/deployments/mainnet/Boba_Adapter.json @@ -194,7 +194,7 @@ ], "numDeployments": 1, "solcInputHash": "80d9895099d6448454133a653020a62d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Boba system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Boba that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Boba.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Boba.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter that excludes the custom bridging logic.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Boba_Adapter.sol\":\"Boba_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Boba_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\\n * that excludes the custom bridging logic.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Boba.\\n * @param target Contract on Boba that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Boba.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x49d48d71aa747ab7deb11ed446f28e7c976b11d7df85e7b97261b3d2c54cfb0e\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Boba system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Boba that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Boba.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Boba.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter that excludes the custom bridging logic.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Boba_Adapter.sol\":\"Boba_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Boba_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\\n * that excludes the custom bridging logic.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Boba.\\n * @param target Contract on Boba that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Boba.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x49d48d71aa747ab7deb11ed446f28e7c976b11d7df85e7b97261b3d2c54cfb0e\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610100604052621e848060a05234801561001857600080fd5b50604051610e93380380610e938339810160408190526100379161006c565b6001600160a01b0391821660805291811660c0521660e0526100b9565b6001600160a01b038116811461006957600080fd5b50565b60008060006060848603121561008157600080fd5b835161008c81610054565b602085015190935061009d81610054565b60408501519092506100ae81610054565b809150509250925092565b60805160a05160c05160e051610d6b61012860003960008181607c01528181610311015261037801526000818160da015281816101a30152610223015260008181610157015281816102dc0152818161041901526104f701526000818161010e01526106d50152610d6b6000f3fe6080604052600436106100655760003560e01c806352c8c75c1161004357806352c8c75c14610130578063cf6e65b714610145578063e6eb8ade1461018e57600080fd5b8063078f29cf1461006a578063146bf4b1146100c85780633cb747bf146100fc575b600080fd5b34801561007657600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156100d457600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561010857600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b61014361013e366004610a89565b6101a1565b005b34801561015157600080fd5b506101797f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100bf565b61014361019c366004610ad6565b6104f1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610376576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561035857600080fd5b505af115801561036c573d6000803e3d6000fd5b505050505061048c565b7f00000000000000000000000000000000000000000000000000000000000000006103b873ffffffffffffffffffffffffffffffffffffffff8616828561055d565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61051d837f00000000000000000000000000000000000000000000000000000000000000008484610698565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161055093929190610ba2565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190610bdb565b6106029190610bf4565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610692908590610748565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610710908790869086908990600401610c33565b600060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b5050505050505050565b60006107aa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661085e9092919063ffffffff16565b80519091501561085957808060200190518101906107c89190610c7a565b610859576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061086d8484600085610877565b90505b9392505050565b606082471015610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610850565b73ffffffffffffffffffffffffffffffffffffffff85163b610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610850565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109b09190610cc8565b60006040518083038185875af1925050503d80600081146109ed576040519150601f19603f3d011682016040523d82523d6000602084013e6109f2565b606091505b5091509150610a02828286610a0d565b979650505050505050565b60608315610a1c575081610870565b825115610a2c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108509190610ce4565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a8457600080fd5b919050565b60008060008060808587031215610a9f57600080fd5b610aa885610a60565b9350610ab660208601610a60565b925060408501359150610acb60608601610a60565b905092959194509250565b600080600060408486031215610aeb57600080fd5b610af484610a60565b9250602084013567ffffffffffffffff80821115610b1157600080fd5b818601915086601f830112610b2557600080fd5b813581811115610b3457600080fd5b876020828501011115610b4657600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610bd2604083018486610b59565b95945050505050565b600060208284031215610bed57600080fd5b5051919050565b60008219821115610c2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610c63606083018587610b59565b905063ffffffff8316604083015295945050505050565b600060208284031215610c8c57600080fd5b8151801515811461087057600080fd5b60005b83811015610cb7578181015183820152602001610c9f565b838111156106925750506000910152565b60008251610cda818460208701610c9c565b9190910192915050565b6020815260008251806020840152610d03816040850160208701610c9c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212207f9bba09fc32ab805ba4eedd30279030757c69a4a4b12e51aea2f961db2c1e5864736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100655760003560e01c806352c8c75c1161004357806352c8c75c14610130578063cf6e65b714610145578063e6eb8ade1461018e57600080fd5b8063078f29cf1461006a578063146bf4b1146100c85780633cb747bf146100fc575b600080fd5b34801561007657600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156100d457600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561010857600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b61014361013e366004610a89565b6101a1565b005b34801561015157600080fd5b506101797f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100bf565b61014361019c366004610ad6565b6104f1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610376576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561035857600080fd5b505af115801561036c573d6000803e3d6000fd5b505050505061048c565b7f00000000000000000000000000000000000000000000000000000000000000006103b873ffffffffffffffffffffffffffffffffffffffff8616828561055d565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61051d837f00000000000000000000000000000000000000000000000000000000000000008484610698565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161055093929190610ba2565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190610bdb565b6106029190610bf4565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610692908590610748565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610710908790869086908990600401610c33565b600060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b5050505050505050565b60006107aa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661085e9092919063ffffffff16565b80519091501561085957808060200190518101906107c89190610c7a565b610859576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061086d8484600085610877565b90505b9392505050565b606082471015610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610850565b73ffffffffffffffffffffffffffffffffffffffff85163b610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610850565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109b09190610cc8565b60006040518083038185875af1925050503d80600081146109ed576040519150601f19603f3d011682016040523d82523d6000602084013e6109f2565b606091505b5091509150610a02828286610a0d565b979650505050505050565b60608315610a1c575081610870565b825115610a2c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108509190610ce4565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a8457600080fd5b919050565b60008060008060808587031215610a9f57600080fd5b610aa885610a60565b9350610ab660208601610a60565b925060408501359150610acb60608601610a60565b905092959194509250565b600080600060408486031215610aeb57600080fd5b610af484610a60565b9250602084013567ffffffffffffffff80821115610b1157600080fd5b818601915086601f830112610b2557600080fd5b813581811115610b3457600080fd5b876020828501011115610b4657600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610bd2604083018486610b59565b95945050505050565b600060208284031215610bed57600080fd5b5051919050565b60008219821115610c2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610c63606083018587610b59565b905063ffffffff8316604083015295945050505050565b600060208284031215610c8c57600080fd5b8151801515811461087057600080fd5b60005b83811015610cb7578181015183820152602001610c9f565b838111156106925750506000910152565b60008251610cda818460208701610c9c565b9190910192915050565b6020815260008251806020840152610d03816040850160208701610c9c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212207f9bba09fc32ab805ba4eedd30279030757c69a4a4b12e51aea2f961db2c1e5864736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Ethereum_Adapter.json b/deployments/mainnet/Ethereum_Adapter.json index feb62a92..79ebc869 100644 --- a/deployments/mainnet/Ethereum_Adapter.json +++ b/deployments/mainnet/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Ethereum_SpokePool.json b/deployments/mainnet/Ethereum_SpokePool.json index d64a6c4b..6ab8bc18 100644 --- a/deployments/mainnet/Ethereum_SpokePool.json +++ b/deployments/mainnet/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "ac469a0c874627ad85d8b93b55e7f3fc", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200466b3803806200466b8339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b608051614382620002e9600039600081816101d901528181610ce601528181610daf0152818161234d01528181612bd30152612c2901526143826000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/LpTokenFactory.json b/deployments/mainnet/LpTokenFactory.json index 88d7c1e5..4c55f8bc 100644 --- a/deployments/mainnet/LpTokenFactory.json +++ b/deployments/mainnet/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Optimism_Adapter.json b/deployments/mainnet/Optimism_Adapter.json index 64a76183..32447c6c 100644 --- a/deployments/mainnet/Optimism_Adapter.json +++ b/deployments/mainnet/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052621e848060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161113538038061113583398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f606101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108ca0152610f606000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/PolygonTokenBridger.json b/deployments/mainnet/PolygonTokenBridger.json index 13ab1495..ea947bd4 100644 --- a/deployments/mainnet/PolygonTokenBridger.json +++ b/deployments/mainnet/PolygonTokenBridger.json @@ -203,7 +203,7 @@ ], "numDeployments": 2, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Polygon_Adapter.json b/deployments/mainnet/Polygon_Adapter.json index 55566036..be7f01a6 100644 --- a/deployments/mainnet/Polygon_Adapter.json +++ b/deployments/mainnet/Polygon_Adapter.json @@ -238,7 +238,7 @@ ], "numDeployments": 1, "solcInputHash": "b20d5afcf396996ae08652b8281973a7", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract DepositManager\",\"name\":\"_depositManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_erc20Predicate\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Matic\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"depositManager\",\"outputs\":[{\"internalType\":\"contract DepositManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"erc20Predicate\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Matic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_depositManager\":\"DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\",\"_erc20Predicate\":\"ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\",\"_fxStateSender\":\"FxStateSender Polygon system contract to send arbitrary messages to L2.\",\"_l1Matic\":\"matic address on l1.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\ninterface IRootChainManager {\\r\\n function depositEtherFor(address user) external payable;\\r\\n\\r\\n function depositFor(\\r\\n address user,\\r\\n address rootToken,\\r\\n bytes calldata depositData\\r\\n ) external;\\r\\n}\\r\\n\\r\\ninterface IFxStateSender {\\r\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\r\\n}\\r\\n\\r\\ninterface DepositManager {\\r\\n function depositERC20ForUser(\\r\\n address token,\\r\\n address user,\\r\\n uint256 amount\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Sends cross chain messages Polygon L2 network.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Polygon_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n IRootChainManager public immutable rootChainManager;\\r\\n IFxStateSender public immutable fxStateSender;\\r\\n DepositManager public immutable depositManager;\\r\\n address public immutable erc20Predicate;\\r\\n address public immutable l1Matic;\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\\r\\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\\r\\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\\r\\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\\r\\n * @param _l1Matic matic address on l1.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n */\\r\\n constructor(\\r\\n IRootChainManager _rootChainManager,\\r\\n IFxStateSender _fxStateSender,\\r\\n DepositManager _depositManager,\\r\\n address _erc20Predicate,\\r\\n address _l1Matic,\\r\\n WETH9 _l1Weth\\r\\n ) {\\r\\n rootChainManager = _rootChainManager;\\r\\n fxStateSender = _fxStateSender;\\r\\n depositManager = _depositManager;\\r\\n erc20Predicate = _erc20Predicate;\\r\\n l1Matic = _l1Matic;\\r\\n l1Weth = _l1Weth;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Polygon.\\r\\n * @param target Contract on Polygon that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n fxStateSender.sendMessageToChild(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Polygon.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n rootChainManager.depositEtherFor{ value: amount }(to);\\r\\n } else if (l1Token == l1Matic) {\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\\r\\n depositManager.depositERC20ForUser(l1Token, to, amount);\\r\\n } else {\\r\\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\\r\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xac06498e0b896c0365fe8410417d10bcc02a4de509a3b815b43cc5e48d91552d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract DepositManager\",\"name\":\"_depositManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_erc20Predicate\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Matic\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"depositManager\",\"outputs\":[{\"internalType\":\"contract DepositManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"erc20Predicate\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Matic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_depositManager\":\"DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\",\"_erc20Predicate\":\"ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\",\"_fxStateSender\":\"FxStateSender Polygon system contract to send arbitrary messages to L2.\",\"_l1Matic\":\"matic address on l1.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\ninterface IRootChainManager {\\r\\n function depositEtherFor(address user) external payable;\\r\\n\\r\\n function depositFor(\\r\\n address user,\\r\\n address rootToken,\\r\\n bytes calldata depositData\\r\\n ) external;\\r\\n}\\r\\n\\r\\ninterface IFxStateSender {\\r\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\r\\n}\\r\\n\\r\\ninterface DepositManager {\\r\\n function depositERC20ForUser(\\r\\n address token,\\r\\n address user,\\r\\n uint256 amount\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Sends cross chain messages Polygon L2 network.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Polygon_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n IRootChainManager public immutable rootChainManager;\\r\\n IFxStateSender public immutable fxStateSender;\\r\\n DepositManager public immutable depositManager;\\r\\n address public immutable erc20Predicate;\\r\\n address public immutable l1Matic;\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\\r\\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\\r\\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\\r\\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\\r\\n * @param _l1Matic matic address on l1.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n */\\r\\n constructor(\\r\\n IRootChainManager _rootChainManager,\\r\\n IFxStateSender _fxStateSender,\\r\\n DepositManager _depositManager,\\r\\n address _erc20Predicate,\\r\\n address _l1Matic,\\r\\n WETH9 _l1Weth\\r\\n ) {\\r\\n rootChainManager = _rootChainManager;\\r\\n fxStateSender = _fxStateSender;\\r\\n depositManager = _depositManager;\\r\\n erc20Predicate = _erc20Predicate;\\r\\n l1Matic = _l1Matic;\\r\\n l1Weth = _l1Weth;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Polygon.\\r\\n * @param target Contract on Polygon that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n fxStateSender.sendMessageToChild(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Polygon.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n rootChainManager.depositEtherFor{ value: amount }(to);\\r\\n } else if (l1Token == l1Matic) {\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\\r\\n depositManager.depositERC20ForUser(l1Token, to, amount);\\r\\n } else {\\r\\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\\r\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xac06498e0b896c0365fe8410417d10bcc02a4de509a3b815b43cc5e48d91552d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6101406040523480156200001257600080fd5b50604051620010193803806200101983398101604081905262000035916200007e565b6001600160a01b0395861660805293851660a05291841660c052831660e052821661010052166101205262000112565b6001600160a01b03811681146200007b57600080fd5b50565b60008060008060008060c087890312156200009857600080fd5b8651620000a58162000065565b6020880151909650620000b88162000065565b6040880151909550620000cb8162000065565b6060880151909450620000de8162000065565b6080880151909350620000f18162000065565b60a0880151909250620001048162000065565b809150509295509295509295565b60805160a05160c05160e0516101005161012051610e79620001a06000396000818160920152818161020b015261028b01526000818161016c01526103a60152600081816101a0015261050901526000818161010401528181610413015261048c01526000818161013801526106810152600081816101d40152818161033f01526105300152610e796000f3fe60806040526004361061007b5760003560e01c8063b28de9e81161004e578063b28de9e81461015a578063b68649761461018e578063bd07018d146101c2578063e6eb8ade146101f657600080fd5b8063146bf4b11461008057806352c8c75c146100dd5780636c7ac9d8146100f2578063a996cabb14610126575b600080fd5b34801561008c57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100f06100eb366004610ba8565b610209565b005b3480156100fe57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561013257600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561016657600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561019a57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b6100f0610204366004610bf5565b610644565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103a4576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156102e457600080fd5b505af11580156102f8573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b15801561038657600080fd5b505af115801561039a573d6000803e3d6000fd5b50505050506105df565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036104ed5761043873ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b6040517f8b9e4f9300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528281166024830152604482018490527f00000000000000000000000000000000000000000000000000000000000000001690638b9e4f9390606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b505050506105df565b61052e73ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161057f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016105ac93929190610cee565b600060405180830381600087803b1580156105c657600080fd5b505af11580156105da573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906106ba90869086908690600401610d30565b600060405180830381600087803b1580156106d457600080fd5b505af11580156106e8573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161071f93929190610d30565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c79190610d9a565b6107d19190610db3565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610861908590610867565b50505050565b60006108c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661097d9092919063ffffffff16565b80519091501561097857808060200190518101906108e79190610df2565b610978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061098c8484600085610996565b90505b9392505050565b606082471015610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161096f565b73ffffffffffffffffffffffffffffffffffffffff85163b610aa6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161096f565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610acf9190610e14565b60006040518083038185875af1925050503d8060008114610b0c576040519150601f19603f3d011682016040523d82523d6000602084013e610b11565b606091505b5091509150610b21828286610b2c565b979650505050505050565b60608315610b3b57508161098f565b825115610b4b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096f9190610e30565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ba357600080fd5b919050565b60008060008060808587031215610bbe57600080fd5b610bc785610b7f565b9350610bd560208601610b7f565b925060408501359150610bea60608601610b7f565b905092959194509250565b600080600060408486031215610c0a57600080fd5b610c1384610b7f565b9250602084013567ffffffffffffffff80821115610c3057600080fd5b818601915086601f830112610c4457600080fd5b813581811115610c5357600080fd5b876020828501011115610c6557600080fd5b6020830194508093505050509250925092565b60005b83811015610c93578181015183820152602001610c7b565b838111156108615750506000910152565b60008151808452610cbc816020860160208601610c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610d276060830184610ca4565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600060208284031215610dac57600080fd5b5051919050565b60008219821115610ded577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610e0457600080fd5b8151801515811461098f57600080fd5b60008251610e26818460208701610c78565b9190910192915050565b60208152600061098f6020830184610ca456fea264697066735822122006c8302b81644d77ec414a1fdc181ef1d45419b0403f705415ee193f8aff341764736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c8063b28de9e81161004e578063b28de9e81461015a578063b68649761461018e578063bd07018d146101c2578063e6eb8ade146101f657600080fd5b8063146bf4b11461008057806352c8c75c146100dd5780636c7ac9d8146100f2578063a996cabb14610126575b600080fd5b34801561008c57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100f06100eb366004610ba8565b610209565b005b3480156100fe57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561013257600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561016657600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561019a57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b6100f0610204366004610bf5565b610644565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103a4576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156102e457600080fd5b505af11580156102f8573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b15801561038657600080fd5b505af115801561039a573d6000803e3d6000fd5b50505050506105df565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036104ed5761043873ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b6040517f8b9e4f9300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528281166024830152604482018490527f00000000000000000000000000000000000000000000000000000000000000001690638b9e4f9390606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b505050506105df565b61052e73ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161057f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016105ac93929190610cee565b600060405180830381600087803b1580156105c657600080fd5b505af11580156105da573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906106ba90869086908690600401610d30565b600060405180830381600087803b1580156106d457600080fd5b505af11580156106e8573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161071f93929190610d30565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c79190610d9a565b6107d19190610db3565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610861908590610867565b50505050565b60006108c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661097d9092919063ffffffff16565b80519091501561097857808060200190518101906108e79190610df2565b610978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061098c8484600085610996565b90505b9392505050565b606082471015610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161096f565b73ffffffffffffffffffffffffffffffffffffffff85163b610aa6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161096f565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610acf9190610e14565b60006040518083038185875af1925050503d8060008114610b0c576040519150601f19603f3d011682016040523d82523d6000602084013e610b11565b606091505b5091509150610b21828286610b2c565b979650505050505050565b60608315610b3b57508161098f565b825115610b4b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096f9190610e30565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ba357600080fd5b919050565b60008060008060808587031215610bbe57600080fd5b610bc785610b7f565b9350610bd560208601610b7f565b925060408501359150610bea60608601610b7f565b905092959194509250565b600080600060408486031215610c0a57600080fd5b610c1384610b7f565b9250602084013567ffffffffffffffff80821115610c3057600080fd5b818601915086601f830112610c4457600080fd5b813581811115610c5357600080fd5b876020828501011115610c6557600080fd5b6020830194508093505050509250925092565b60005b83811015610c93578181015183820152602001610c7b565b838111156108615750506000910152565b60008151808452610cbc816020860160208601610c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610d276060830184610ca4565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600060208284031215610dac57600080fd5b5051919050565b60008219821115610ded577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610e0457600080fd5b8151801515811461098f57600080fd5b60008251610e26818460208701610c78565b9190910192915050565b60208152600061098f6020830184610ca456fea264697066735822122006c8302b81644d77ec414a1fdc181ef1d45419b0403f705415ee193f8aff341764736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json b/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json index 9c65fe4f..638f2fec 100644 --- a/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json +++ b/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json b/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json index 8192e2d9..f9b52656 100644 --- a/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json +++ b/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Contract is paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Enables the owner of the protocol to haircut reserves in the event of an irrecoverable loss of funds on\r\n * one of the L2s. Consider funds are leant out onto a L2 that dies irrecoverably. This value will offset the\r\n * exchangeRateCurrent such that all LPs receive a pro rata loss of the the reserves. Should be used in conjunction\r\n * with pause logic to prevent LPs from adding/withdrawing liquidity during the haircut process.\r\n * Callable only by owner.\r\n * @param l1Token Token to execute the haircut on.\r\n * @param haircutAmount The amount of reserves to haircut the LPs by.\r\n */\r\n function haircutReserves(address l1Token, int256 haircutAmount) public onlyOwner nonReentrant {\r\n // Note that we do not call sync first in this method. The Owner should call this manually before haircutting.\r\n // This is done in the event sync is reverting due to too low balanced in the contract relative to bond amount.\r\n pooledTokens[l1Token].utilizedReserves -= haircutAmount;\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant unpaused {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant unpaused {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Contract is paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Enables the owner of the protocol to haircut reserves in the event of an irrecoverable loss of funds on\r\n * one of the L2s. Consider funds are leant out onto a L2 that dies irrecoverably. This value will offset the\r\n * exchangeRateCurrent such that all LPs receive a pro rata loss of the the reserves. Should be used in conjunction\r\n * with pause logic to prevent LPs from adding/withdrawing liquidity during the haircut process.\r\n * Callable only by owner.\r\n * @param l1Token Token to execute the haircut on.\r\n * @param haircutAmount The amount of reserves to haircut the LPs by.\r\n */\r\n function haircutReserves(address l1Token, int256 haircutAmount) public onlyOwner nonReentrant {\r\n // Note that we do not call sync first in this method. The Owner should call this manually before haircutting.\r\n // This is done in the event sync is reverting due to too low balanced in the contract relative to bond amount.\r\n pooledTokens[l1Token].utilizedReserves -= haircutAmount;\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant unpaused {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant unpaused {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 9303e25d..43633ef5 100644 --- a/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json b/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json index a86e6ce1..f5967914 100644 --- a/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json +++ b/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json @@ -2,28 +2,28 @@ "language": "Solidity", "sources": { "contracts/Succinct_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./external/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be misinterpreted.\n // Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(\n msg.sender == succinctTargetAmb && _senderAddress == hubPool && _sourceChainId == hubChainId,\n \"Invalid message\"\n );\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./external/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be misinterpreted.\n // Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(\n msg.sender == succinctTargetAmb && _senderAddress == hubPool && _sourceChainId == hubChainId,\n \"Invalid message\"\n );\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 updatedRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n struct DepositUpdate {\n uint32 depositId;\n uint256 originChainId;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit and fill functions. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(updatedRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: amount,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (relayExecution.maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = relayExecution.maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Note: since _computeAmountPostFees is typicaly intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n }\n }\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n relayFills[relayExecution.relayHash] + fillAmountPreFees,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n uint256 endingFillAmount,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, it's an initial 0-fill, or a partial fill has already happened, do nothing, as these\n // should not impact the count.\n if (useContractFunds || endingFillAmount == 0 || startingFillAmount > 0) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo;\n // This separate struct is created entirely to avoid stack too deep errors.\n {\n relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n }\n\n {\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor,\n bytes memory message\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor,\n message\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 updatedRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n struct DepositUpdate {\n uint32 depositId;\n uint256 originChainId;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit and fill functions. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(updatedRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: amount,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (relayExecution.maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = relayExecution.maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Note: since _computeAmountPostFees is typicaly intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n }\n }\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n relayFills[relayExecution.relayHash] + fillAmountPreFees,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n uint256 endingFillAmount,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, it's an initial 0-fill, or a partial fill has already happened, do nothing, as these\n // should not impact the count.\n if (useContractFunds || endingFillAmount == 0 || startingFillAmount > 0) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo;\n // This separate struct is created entirely to avoid stack too deep errors.\n {\n relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n }\n\n {\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor,\n bytes memory message\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor,\n message\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/interfaces/WETH9Interface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9Interface {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9Interface {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" }, "contracts/external/SuccinctInterfaces.sol": { "content": "pragma solidity ^0.8.0;\n\n// These interfaces are a subset of the Succinct interfaces here: https://github.com/succinctlabs/telepathy-contracts.\n\n// This interface should be implemented by any contract wanting to receive messages sent over the Succinct bridge.\ninterface ITelepathyHandler {\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external returns (bytes4);\n}\n\n// This interface represents the contract that we call into to send messages over the Succinct AMB.\ninterface ITelepathyBroadcaster {\n function send(\n uint16 _recipientChainId,\n address _recipientAddress,\n bytes calldata _data\n ) external returns (bytes32);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/upgradeable/MultiCallerUpgradeable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title MockSpokePool\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title MockSpokePool\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/upgradeable/EIP712CrossChainUpgradeable.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" @@ -50,13 +50,13 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n function safeTransfer(\n IERC20Upgradeable token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20Upgradeable token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/token/ERC20/IERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" @@ -98,10 +98,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" diff --git a/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json b/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json index 443a80d8..537422d6 100644 --- a/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json +++ b/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,43 +113,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -158,22 +158,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json b/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json index 0243bee8..206a1490 100644 --- a/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json +++ b/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n function createRetryableTicketNoRefundAliasRewrite(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n function createRetryableTicketNoRefundAliasRewrite(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json b/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json index 9a0dc4f6..e4367cfe 100644 --- a/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json +++ b/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json @@ -2,13 +2,13 @@ "language": "Solidity", "sources": { "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/IERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" diff --git a/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json b/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json index d2f1997a..d8174d10 100644 --- a/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json +++ b/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json b/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json index 4e7aab6e..5c9d5d01 100644 --- a/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json +++ b/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\r\n */\r\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\r\n {}\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\r\n */\r\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\r\n {}\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json b/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json index 74e62cf1..a9377e90 100644 --- a/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json +++ b/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index 2a6425e5..a0cc1d52 100644 --- a/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json b/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json index 08c3cc5c..52e7ecd2 100644 --- a/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json +++ b/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/optimism-kovan/Optimism_SpokePool.json b/deployments/optimism-kovan/Optimism_SpokePool.json index 2f62559d..6aca2574 100644 --- a/deployments/optimism-kovan/Optimism_SpokePool.json +++ b/deployments/optimism-kovan/Optimism_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\n\\n/**\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\n // unused by bridge but included for future compatibility.\\n uint32 public l1Gas = 5_000_000;\\n\\n // ETH is an ERC20 on OVM.\\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\\n\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\n mapping(address => address) public tokenBridges;\\n\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\n event SetL1Gas(uint32 indexed newL1Gas);\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\n\\n /**\\n * @notice Construct the OVM SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address timerAddress\\n )\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\\n {}\\n\\n /*******************************************\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\n *******************************************/\\n\\n /**\\n * @notice Change L1 gas limit. Callable only by admin.\\n * @param newl1Gas New L1 gas limit to set.\\n */\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\n l1Gas = newl1Gas;\\n emit SetL1Gas(newl1Gas);\\n }\\n\\n /**\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\n * @param tokenBridge Address of token bridge\\n */\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\n tokenBridges[l2Token] = tokenBridge;\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 totalRelayAmount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n totalRelayAmount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\n // on the OVM.\\n function _depositEthToWeth() internal {\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\n }\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\n }\\n IL2ERC20Bridge(\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\n ).withdrawTo(\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\n }\\n\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\n}\\n\",\"keccak256\":\"0xe8a9ceea10e37bc4a1aef16a3337811d176cf92520b103272d86e472f450d2a1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\n\\n/**\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\n // unused by bridge but included for future compatibility.\\n uint32 public l1Gas = 5_000_000;\\n\\n // ETH is an ERC20 on OVM.\\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\\n\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\n mapping(address => address) public tokenBridges;\\n\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\n event SetL1Gas(uint32 indexed newL1Gas);\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\n\\n /**\\n * @notice Construct the OVM SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address timerAddress\\n )\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\\n {}\\n\\n /*******************************************\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\n *******************************************/\\n\\n /**\\n * @notice Change L1 gas limit. Callable only by admin.\\n * @param newl1Gas New L1 gas limit to set.\\n */\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\n l1Gas = newl1Gas;\\n emit SetL1Gas(newl1Gas);\\n }\\n\\n /**\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\n * @param tokenBridge Address of token bridge\\n */\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\n tokenBridges[l2Token] = tokenBridge;\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 totalRelayAmount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n totalRelayAmount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\n // on the OVM.\\n function _depositEthToWeth() internal {\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\n }\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\n }\\n IL2ERC20Bridge(\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\n ).withdrawTo(\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\n }\\n\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\n}\\n\",\"keccak256\":\"0xe8a9ceea10e37bc4a1aef16a3337811d176cf92520b103272d86e472f450d2a1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b4017905573deaddeaddeaddeaddeaddeaddeaddeaddead000060a0523480156200005357600080fd5b5060405162004c8938038062004c89833981016040819052620000769162000269565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273420000000000000000000000000000000000000683620000e08462000104565b620000eb83620001aa565b506001600160a01b031660805250620002b39350505050565b6001600160a01b038116620001605760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002025760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000157565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200026457600080fd5b919050565b6000806000606084860312156200027f57600080fd5b6200028a846200024c565b92506200029a602085016200024c565b9150620002aa604085016200024c565b90509250925092565b60805160a05161496a6200031f600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d2f5cc3730c17bef6c253d4fdf81eecdd0f59a76612528a3f30f63eb1b2c7eca64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d2f5cc3730c17bef6c253d4fdf81eecdd0f59a76612528a3f30f63eb1b2c7eca64736f6c634300080d0033", "devdoc": { diff --git a/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index 2a6425e5..a0cc1d52 100644 --- a/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/optimism/Optimism_SpokePool.json b/deployments/optimism/Optimism_SpokePool.json index 7a911374..109a09c9 100644 --- a/deployments/optimism/Optimism_SpokePool.json +++ b/deployments/optimism/Optimism_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Optimism SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Optimism Spoke pool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Optimism Spoke pool.\\r\\n */\\r\\ncontract Optimism_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Optimism SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n Lib_PredeployAddresses.OVM_ETH,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x73c37ddf9651c2b34bfc877502b44bc0f271498206dfe4446e7b653567920a53\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Optimism SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Optimism Spoke pool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Optimism Spoke pool.\\r\\n */\\r\\ncontract Optimism_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Optimism SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n Lib_PredeployAddresses.OVM_ETH,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x73c37ddf9651c2b34bfc877502b44bc0f271498206dfe4446e7b653567920a53\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b401790553480156200003b57600080fd5b5060405162004c9738038062004c978339810160408190526200005e9162000277565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273deaddeaddeaddeaddeaddeaddeaddeaddead00007342000000000000000000000000000000000000068484848383620000e18462000112565b620000ec83620001b8565b506001600160a01b039081166080529490941660a05250620002c1975050505050505050565b6001600160a01b0381166200016e5760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002105760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000165565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200027257600080fd5b919050565b6000806000606084860312156200028d57600080fd5b62000298846200025a565b9250620002a8602085016200025a565b9150620002b8604085016200025a565b90509250925092565b60805160a05161496a6200032d600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212209da4bba922e72e8a4d613325bde7422470ee1aea7d82220d65f7da5c44f56f0c64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212209da4bba922e72e8a4d613325bde7422470ee1aea7d82220d65f7da5c44f56f0c64736f6c634300080d0033", "devdoc": { diff --git a/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 9303e25d..43633ef5 100644 --- a/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon-mumbai/MintableERC1155.json b/deployments/polygon-mumbai/MintableERC1155.json index e66d2b31..bb32035d 100644 --- a/deployments/polygon-mumbai/MintableERC1155.json +++ b/deployments/polygon-mumbai/MintableERC1155.json @@ -511,7 +511,7 @@ "args": [], "numDeployments": 3, "solcInputHash": "200193942e0f09d7ebb5ccce1bc305e7", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\ncontract MintableERC1155 is ERC1155, Ownable {\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x1ce6820f23820d4d6dbd48b168e6de51efe1216c4880e2f2e0bb3143d58d7ed5\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\ncontract MintableERC1155 is ERC1155, Ownable {\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x1ce6820f23820d4d6dbd48b168e6de51efe1216c4880e2f2e0bb3143d58d7ed5\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080346200012657602081016001600160401b03811182821017620001105760405260008091526002546001908181811c9116801562000105575b6020821014620000f157601f8111620000a7575b600283905560038054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08680a3611fc990816200012c8239f35b60028352601f0160051c7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace908101905b818110620000e657506200004e565b8381558201620000d7565b634e487b7160e01b83526022600452602483fd5b90607f16906200003a565b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea26469706673582212204649af28b2218246749413731aaab257fc72268b5a9c227716987edfd17c6b3e64736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea26469706673582212204649af28b2218246749413731aaab257fc72268b5a9c227716987edfd17c6b3e64736f6c63430008120033", "devdoc": { diff --git a/deployments/polygon-mumbai/PolygonTokenBridger.json b/deployments/polygon-mumbai/PolygonTokenBridger.json index 9f71acea..bf0831dd 100644 --- a/deployments/polygon-mumbai/PolygonTokenBridger.json +++ b/deployments/polygon-mumbai/PolygonTokenBridger.json @@ -219,7 +219,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon-mumbai/Polygon_SpokePool.json b/deployments/polygon-mumbai/Polygon_SpokePool.json index c8dbfc13..d8a9d979 100644 --- a/deployments/polygon-mumbai/Polygon_SpokePool.json +++ b/deployments/polygon-mumbai/Polygon_SpokePool.json @@ -1227,7 +1227,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790556007805460ff60a01b191690553480156200003457600080fd5b5060405162004cee38038062004cee833981016040819052620000579162000238565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055848484836200008784620000d7565b62000092836200017d565b506001600160a01b03908116608052600780549982166001600160a01b03199a8b161790556006805495909116949098169390931790965550620002cc945050505050565b6001600160a01b038116620001335760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001d55760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c206164647265737300000000000000000000000060448201526064016200012a565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b6001600160a01b03811681146200023557600080fd5b50565b60008060008060008060c087890312156200025257600080fd5b86516200025f816200021f565b602088015190965062000272816200021f565b604088015190955062000285816200021f565b606088015190945062000298816200021f565b6080880151909350620002ab816200021f565b60a0880151909250620002be816200021f565b809150509295509295509295565b6080516149dc620003126000396000818161021c01528181610e6b01528181610f3401528181611ef10152818161276d0152818161308301526130d901526149dc6000f3fe6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json b/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json index cb04c7ce..8f32c282 100644 --- a/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json +++ b/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json b/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json index 042e6dae..78455c1b 100644 --- a/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json +++ b/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @dev Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n *\n * NOTE: Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @dev Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n *\n * NOTE: Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json b/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json index 127623b2..bb0f1a27 100644 --- a/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json +++ b/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\ncontract MintableERC1155 is ERC1155PresetMinterPauser {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256[] amounts);\n\n constructor() ERC1155PresetMinterPauser(\"\") {}\n\n /**\n * @dev Creates `amounts[i]` new tokens for `recipients[i]` of toke type `tokenId`.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256[] memory amounts\n ) public {\n require(recipients.length == amounts.length, \"MintableERC1155: recipients and amounts length mismatch\");\n\n for (uint256 i = 0; i < recipients.length; i++) {\n mint(recipients[i], tokenId, amounts[i], \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amounts);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to set uri\");\n\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for token types.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\ncontract MintableERC1155 is ERC1155PresetMinterPauser {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256[] amounts);\n\n constructor() ERC1155PresetMinterPauser(\"\") {}\n\n /**\n * @dev Creates `amounts[i]` new tokens for `recipients[i]` of toke type `tokenId`.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256[] memory amounts\n ) public {\n require(recipients.length == amounts.length, \"MintableERC1155: recipients and amounts length mismatch\");\n\n for (uint256 i = 0; i < recipients.length; i++) {\n mint(recipients[i], tokenId, amounts[i], \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amounts);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to set uri\");\n\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for token types.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/presets/ERC1155PresetMinterPauser.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC1155.sol\";\nimport \"../extensions/ERC1155Burnable.sol\";\nimport \"../extensions/ERC1155Pausable.sol\";\nimport \"../../../access/AccessControlEnumerable.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev {ERC1155} token, including:\n *\n * - ability for holders to burn (destroy) their tokens\n * - a minter role that allows for token minting (creation)\n * - a pauser role that allows to stop all token transfers\n *\n * This contract uses {AccessControl} to lock permissioned functions using the\n * different roles - head to its documentation for details.\n *\n * The account that deploys the contract will be granted the minter and pauser\n * roles, as well as the default admin role, which will let it grant both minter\n * and pauser roles to other accounts.\n *\n * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._\n */\ncontract ERC1155PresetMinterPauser is Context, AccessControlEnumerable, ERC1155Burnable, ERC1155Pausable {\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n /**\n * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, and `PAUSER_ROLE` to the account that\n * deploys the contract.\n */\n constructor(string memory uri) ERC1155(uri) {\n _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());\n\n _setupRole(MINTER_ROLE, _msgSender());\n _setupRole(PAUSER_ROLE, _msgSender());\n }\n\n /**\n * @dev Creates `amount` new tokens for `to`, of token type `id`.\n *\n * See {ERC1155-_mint}.\n *\n * Requirements:\n *\n * - the caller must have the `MINTER_ROLE`.\n */\n function mint(\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) public virtual {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to mint\");\n\n _mint(to, id, amount, data);\n }\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.\n */\n function mintBatch(\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) public virtual {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to mint\");\n\n _mintBatch(to, ids, amounts, data);\n }\n\n /**\n * @dev Pauses all token transfers.\n *\n * See {ERC1155Pausable} and {Pausable-_pause}.\n *\n * Requirements:\n *\n * - the caller must have the `PAUSER_ROLE`.\n */\n function pause() public virtual {\n require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have pauser role to pause\");\n _pause();\n }\n\n /**\n * @dev Unpauses all token transfers.\n *\n * See {ERC1155Pausable} and {Pausable-_unpause}.\n *\n * Requirements:\n *\n * - the caller must have the `PAUSER_ROLE`.\n */\n function unpause() public virtual {\n require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have pauser role to unpause\");\n _unpause();\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId)\n public\n view\n virtual\n override(AccessControlEnumerable, ERC1155)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n function _beforeTokenTransfer(\n address operator,\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual override(ERC1155, ERC1155Pausable) {\n super._beforeTokenTransfer(operator, from, to, ids, amounts, data);\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index 2a6425e5..a0cc1d52 100644 --- a/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/MintableERC1155.json b/deployments/polygon/MintableERC1155.json index b53bda8f..77928bc6 100644 --- a/deployments/polygon/MintableERC1155.json +++ b/deployments/polygon/MintableERC1155.json @@ -511,7 +511,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "ea9229ed188f1300c4a413d030dbf1b6", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"title\":\"MintableERC1155\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"notice\":\"Ownable contract enabling owner to airdrop many recipients the same token ID at once\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\n/**\\n * @title MintableERC1155\\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\\n */\\ncontract MintableERC1155 is ERC1155, Ownable {\\n // Maps `tokenId` to metadata URI `tokenURI`\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\\n // to allow for IPFS URIs.\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x3278a4a107e88bf5a9c63672ea4fb33f5e7fa86e2c089f73bafa681eb6bc3641\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"title\":\"MintableERC1155\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"notice\":\"Ownable contract enabling owner to airdrop many recipients the same token ID at once\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\n/**\\n * @title MintableERC1155\\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\\n */\\ncontract MintableERC1155 is ERC1155, Ownable {\\n // Maps `tokenId` to metadata URI `tokenURI`\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\\n // to allow for IPFS URIs.\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x3278a4a107e88bf5a9c63672ea4fb33f5e7fa86e2c089f73bafa681eb6bc3641\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080346200012657602081016001600160401b03811182821017620001105760405260008091526002546001908181811c9116801562000105575b6020821014620000f157601f8111620000a7575b600283905560038054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08680a3611fc990816200012c8239f35b60028352601f0160051c7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace908101905b818110620000e657506200004e565b8381558201620000d7565b634e487b7160e01b83526022600452602483fd5b90607f16906200003a565b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea2646970667358221220c3377770cdb03b603ff928387edb7dc3ad004b20210900a98759b0565733980764736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea2646970667358221220c3377770cdb03b603ff928387edb7dc3ad004b20210900a98759b0565733980764736f6c63430008120033", "devdoc": { diff --git a/deployments/polygon/PolygonTokenBridger.json b/deployments/polygon/PolygonTokenBridger.json index 9106e24a..1da54729 100644 --- a/deployments/polygon/PolygonTokenBridger.json +++ b/deployments/polygon/PolygonTokenBridger.json @@ -219,7 +219,7 @@ ], "numDeployments": 2, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon/Polygon_SpokePool.json b/deployments/polygon/Polygon_SpokePool.json index 5e66b209..5fbea7ea 100644 --- a/deployments/polygon/Polygon_SpokePool.json +++ b/deployments/polygon/Polygon_SpokePool.json @@ -1227,7 +1227,7 @@ ], "numDeployments": 1, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790556007805460ff60a01b191690553480156200003457600080fd5b5060405162004cee38038062004cee833981016040819052620000579162000238565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055848484836200008784620000d7565b62000092836200017d565b506001600160a01b03908116608052600780549982166001600160a01b03199a8b161790556006805495909116949098169390931790965550620002cc945050505050565b6001600160a01b038116620001335760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001d55760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c206164647265737300000000000000000000000060448201526064016200012a565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b6001600160a01b03811681146200023557600080fd5b50565b60008060008060008060c087890312156200025257600080fd5b86516200025f816200021f565b602088015190965062000272816200021f565b604088015190955062000285816200021f565b606088015190945062000298816200021f565b6080880151909350620002ab816200021f565b60a0880151909250620002be816200021f565b809150509295509295509295565b6080516149dc620003126000396000818161021c01528181610e6b01528181610f3401528181611ef10152818161276d0152818161308301526130d901526149dc6000f3fe6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 9303e25d..43633ef5 100644 --- a/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json b/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json index 74e62cf1..a9377e90 100644 --- a/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json +++ b/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json b/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json index 8a801880..fcfa4176 100644 --- a/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json +++ b/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" diff --git a/deployments/rinkeby/Arbitrum_Adapter.json b/deployments/rinkeby/Arbitrum_Adapter.json index 5d851f90..70186d2d 100644 --- a/deployments/rinkeby/Arbitrum_Adapter.json +++ b/deployments/rinkeby/Arbitrum_Adapter.json @@ -224,7 +224,7 @@ "args": ["0x578BAde599406A8fE3d24Fd7f7211c0911F5B29e", "0x70C143928eCfFaf9F5b406f7f4fC28Dc43d68380"], "numDeployments": 1, "solcInputHash": "fc82eeb0fff4196cd4e0dfec8a3b3aca", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xbdebabe1e5a8750542eae714d268cf9c3b18c8bfe8cacce431ddefe6bcaf4334\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xbdebabe1e5a8750542eae714d268cf9c3b18c8bfe8cacce431ddefe6bcaf4334\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052621e8480608052662386f26fc1000060a05264012a05f20060c05234801561002c57600080fd5b5060405161128438038061128483398101604081905261004b91610080565b6001600160a01b039182166101005216610120523360e0526100ba565b6001600160a01b038116811461007d57600080fd5b50565b6000806040838503121561009357600080fd5b825161009e81610068565b60208401519092506100af81610068565b809150509250929050565b60805160a05160c05160e051610100516101205161111a61016a6000396000818160d501528181610333015261047001526000818161014301526105cd0152600081816101ab0152818161062e015261064f0152600081816101770152818161028b015281816104c70152610691015260008181610228015281816102b5015281816103c5015261060d0152600081816101df01528181610269015281816104a50152610670015261111a6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212208a27fef820b6942c0cf40e5cb9184416af0fd6bd08e2b4c6a9bfebf2716b4a1264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212208a27fef820b6942c0cf40e5cb9184416af0fd6bd08e2b4c6a9bfebf2716b4a1264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Ethereum_Adapter.json b/deployments/rinkeby/Ethereum_Adapter.json index 1c3eab16..31da045e 100644 --- a/deployments/rinkeby/Ethereum_Adapter.json +++ b/deployments/rinkeby/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n // solhint-disable-next-line no-inline-assembly\\n\\n bool success;\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd553b891966b6d01d77af8eccc394b7554c3fce1275e6470feecb72cbe173ae4\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n // solhint-disable-next-line no-inline-assembly\\n\\n bool success;\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd553b891966b6d01d77af8eccc394b7554c3fce1275e6470feecb72cbe173ae4\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107fa806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c36600461056e565b610056565b005b6100416100513660046105ea565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff85168284610123565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6100e682826101b5565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610117929190610744565b60405180910390a15050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101b0908490610237565b505050565b600060208201825160008082846000895af192505050806101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b6000610299826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103439092919063ffffffff16565b8051909150156101b057808060200190518101906102b79190610773565b6101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161022e565b6060610352848460008561035c565b90505b9392505050565b6060824710156103ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161022e565b73ffffffffffffffffffffffffffffffffffffffff85163b61046c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161022e565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104959190610795565b60006040518083038185875af1925050503d80600081146104d2576040519150601f19603f3d011682016040523d82523d6000602084013e6104d7565b606091505b50915091506104e78282866104f2565b979650505050505050565b60608315610501575081610355565b8251156105115782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161022e91906107b1565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056957600080fd5b919050565b6000806000806080858703121561058457600080fd5b61058d85610545565b935061059b60208601610545565b9250604085013591506105b060608601610545565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156105fd57600080fd5b61060683610545565b9150602083013567ffffffffffffffff8082111561062357600080fd5b818501915085601f83011261063757600080fd5b813581811115610649576106496105bb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561068f5761068f6105bb565b816040528281528860208487010111156106a857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156106e55781810151838201526020016106cd565b838111156106f4576000848401525b50505050565b600081518084526107128160208601602086016106ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061035260408301846106fa565b60006020828403121561078557600080fd5b8151801515811461035557600080fd5b600082516107a78184602087016106ca565b9190910192915050565b60208152600061035560208301846106fa56fea2646970667358221220c375741f9f8699c2539c58570c2a4ba4c1e9099e507ad943cb7b7cfe570455d264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c36600461056e565b610056565b005b6100416100513660046105ea565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff85168284610123565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6100e682826101b5565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610117929190610744565b60405180910390a15050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101b0908490610237565b505050565b600060208201825160008082846000895af192505050806101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b6000610299826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103439092919063ffffffff16565b8051909150156101b057808060200190518101906102b79190610773565b6101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161022e565b6060610352848460008561035c565b90505b9392505050565b6060824710156103ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161022e565b73ffffffffffffffffffffffffffffffffffffffff85163b61046c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161022e565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104959190610795565b60006040518083038185875af1925050503d80600081146104d2576040519150601f19603f3d011682016040523d82523d6000602084013e6104d7565b606091505b50915091506104e78282866104f2565b979650505050505050565b60608315610501575081610355565b8251156105115782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161022e91906107b1565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056957600080fd5b919050565b6000806000806080858703121561058457600080fd5b61058d85610545565b935061059b60208601610545565b9250604085013591506105b060608601610545565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156105fd57600080fd5b61060683610545565b9150602083013567ffffffffffffffff8082111561062357600080fd5b818501915085601f83011261063757600080fd5b813581811115610649576106496105bb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561068f5761068f6105bb565b816040528281528860208487010111156106a857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156106e55781810151838201526020016106cd565b838111156106f4576000848401525b50505050565b600081518084526107128160208601602086016106ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061035260408301846106fa565b60006020828403121561078557600080fd5b8151801515811461035557600080fd5b600082516107a78184602087016106ca565b9190910192915050565b60208152600061035560208301846106fa56fea2646970667358221220c375741f9f8699c2539c58570c2a4ba4c1e9099e507ad943cb7b7cfe570455d264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Ethereum_SpokePool.json b/deployments/rinkeby/Ethereum_SpokePool.json index a2a6f04a..d1e8f2d5 100644 --- a/deployments/rinkeby/Ethereum_SpokePool.json +++ b/deployments/rinkeby/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 2, "solcInputHash": "1bf8793c065ccb196e5a60f53c731ca8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n bytes32 indexed relayHash,\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\\r\\n for (uint32 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint32).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 relayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayHash,\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0xeb7a64b4ec0592d18254c802d35779fc6aabfca5c6817c52b4344a3946e5654e\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xbd436408b1294166c3459d9f23f80358ae99e95b95b474a99525949e3bf8569d\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n bytes32 indexed relayHash,\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\\r\\n for (uint32 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint32).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 relayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayHash,\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0xeb7a64b4ec0592d18254c802d35779fc6aabfca5c6817c52b4344a3946e5654e\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xbd436408b1294166c3459d9f23f80358ae99e95b95b474a99525949e3bf8569d\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004676380380620046768339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b60805161438d620002e9600039600081816101d901528181610ce601528181610daf0152818161236501528181612bde0152612c34015261438d6000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b50610245610240366004613678565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613774565b6106b0565b3480156102a057600080fd5b506102456102af36600461378f565b61073d565b3480156102c057600080fd5b506102456102cf3660046137b6565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137f6565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b610245610325366004613829565b610ab1565b34801561033657600080fd5b5061024561034536600461388f565b610f28565b34801561035657600080fd5b506103856103653660046138b1565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138db565b6110cf565b34801561044d57600080fd5b5061024561045c36600461378f565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e6366004613979565b6112ff565b60405161021c9190613a64565b34801561050457600080fd5b50610245610513366004613ae4565b6114d9565b34801561052457600080fd5b50610245610533366004613774565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c42565b6115ab565b34801561059157600080fd5b506105a56105a036600461378f565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d536600461378f565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613774565b611737565b34801561061357600080fd5b50610245610622366004613cb1565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611e17565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e98565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611e17565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611e17565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d8f565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dd7565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613dfc565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f84565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612060565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e24565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611e17565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120f1565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612168565b905060006111c782848b886000612198565b90506111d882828a88876000612445565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611e17565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e47565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134bc565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e47565b90506020028101906113eb9190613e76565b6040516113f9929190613edb565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613eeb565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b808484815181106114b2576114b2613e47565b6020026020010181905250505080806114ca90613f6c565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61257a565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611e17565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126f9565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127e5565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613fa4565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120f1565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127e5565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612168565b9050600061196982848d896000612198565b905061197a82828c89876000612445565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e47565b90600052602060002090600302019050611b6d81600101548484612882565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128bf565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff16612900565b60408301515160005b8163ffffffff168163ffffffff161015611d1157600085604001518263ffffffff1681518110611ca357611ca3613e47565b602002602001015190506000811115611d0857611d088660a001518363ffffffff1681518110611cd557611cd5613e47565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50600101611c71565b50835115611daa57611d2284612994565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611da192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611e08959493929190614048565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a38565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008160405160200161217b91906140a6565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121d057506706f05b59d3b200008560c0015167ffffffffffffffff16105b612236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106122b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122c15750600061243c565b6122da84848760c001516122d5919061414d565b612b44565b600087815260056020526040812054606088015192935086926122fd9190614170565b9050828110156123265780925061232383868960c0015161231e919061414d565b612b7e565b91505b60008881526005602052604081208054859290612344908490614187565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123cc57836123b95760408701516123b99073ffffffffffffffffffffffffffffffffffffffff16333085611f84565b6123c7876020015183612ba7565b612439565b83612406576123c7338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f84909392919063ffffffff16565b612439876020015183896040015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f60405161256a9c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264f60038463ffffffff168154811061263657612636613e47565b9060005260206000209060030201600001548284612ce8565b6126b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126c082612168565b905060006126d78284856060015160006001612198565b90506126e98282600080876001612445565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286c82612d00565b9050612879878285612d3b565b50505050505050565b60006128b582858560405160200161289a919061419f565b60405160208183030381529060405280519060200120612dd9565b90505b9392505050565b6000806128ce61010084614269565b905060006128de6101008561427d565b6000928352602095909552506040902054600190931b92831690921492915050565b600061290e61010083614269565b9050600061291e6101008461427d565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fde565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614291565b6000612a9a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612def9092919063ffffffff16565b8051909150156106ab5780806020019051810190612ab89190614291565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b5882670de0b6b3a76400006142ae565b67ffffffffffffffff16612b7484670de0b6b3a76400006142cf565b6128b89190614269565b6000670de0b6b3a7640000612b9383826142ae565b612b749067ffffffffffffffff16856142cf565b73ffffffffffffffffffffffffffffffffffffffff82163b15612c055761103e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838361293e565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8d57600080fd5b505af1158015612ca1573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128b582858560405160200161289a91906140a6565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161217b565b612d458282612dfe565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612de68584612e22565b14949350505050565b60606128b58484600085612e8e565b6000806000612e0d8585613024565b91509150612e1a81613092565b509392505050565b600081815b8451811015612e1a576000858281518110612e4457612e44613e47565b60200260200101519050808311612e6a5760008381526020829052604090209250612e7b565b600081815260208490526040902092505b5080612e8681613f6c565b915050612e27565b606082471015612f20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fc7919061430c565b60006040518083038185875af1925050503d8060008114613004576040519150601f19603f3d011682016040523d82523d6000602084013e613009565b606091505b50915091506130198282866132e6565b979650505050505050565b600080825160410361305a5760208301516040840151606085015160001a61304e87828585613339565b9450945050505061308b565b82516040036130835760208301516040840151613078868383613451565b93509350505061308b565b506000905060025b9250929050565b60008160048111156130a6576130a6614328565b036130ae5750565b60018160048111156130c2576130c2614328565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b600281600481111561313d5761313d614328565b036131a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131b8576131b8614328565b03613245576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561325957613259614328565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132f55750816128b8565b8251156133055782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156133705750600090506003613448565b8460ff16601b1415801561338857508460ff16601c14155b156133995750600090506004613448565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133ed573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661344157600060019250925050613448565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161348760ff86901c601b614187565b905061349587828885613339565b935093505050935093915050565b803563ffffffff811681146134b757600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561350e5761350e6134bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561355b5761355b6134bc565b604052919050565b600067ffffffffffffffff82111561357d5761357d6134bc565b5060051b60200190565b600082601f83011261359857600080fd5b813560206135ad6135a883613563565b613514565b82815260059290921b840181019181810190868411156135cc57600080fd5b8286015b848110156135e757803583529183019183016135d0565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134b757600080fd5b600082601f83011261362757600080fd5b813560206136376135a883613563565b82815260059290921b8401810191818101908684111561365657600080fd5b8286015b848110156135e75761366b816135f2565b835291830191830161365a565b60008060006060848603121561368d57600080fd5b613696846134a3565b9250602084013567ffffffffffffffff808211156136b357600080fd5b9085019060c082880312156136c757600080fd5b6136cf6134eb565b82358152602083013560208201526040830135828111156136ef57600080fd5b6136fb89828601613587565b60408301525061370d606084016134a3565b606082015261371e608084016135f2565b608082015260a08301358281111561373557600080fd5b61374189828601613616565b60a0830152509350604086013591508082111561375d57600080fd5b5061376a86828701613587565b9150509250925092565b60006020828403121561378657600080fd5b6128b8826135f2565b6000602082840312156137a157600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137cb57600080fd5b6137d4846135f2565b92506020840135915060408401356137eb816137a8565b809150509250925092565b60006020828403121561380857600080fd5b6128b8826134a3565b803567ffffffffffffffff811681146134b757600080fd5b60008060008060008060c0878903121561384257600080fd5b61384b876135f2565b9550613859602088016135f2565b9450604087013593506060870135925061387560808801613811565b915061388360a088016134a3565b90509295509295509295565b600080604083850312156138a257600080fd5b50508035926020909101359150565b600080604083850312156138c457600080fd5b6138cd836135f2565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138fb57600080fd5b6139048b6135f2565b995061391260208c016135f2565b985061392060408c016135f2565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061394a60e08c01613811565b92506139596101008c01613811565b91506139686101208c016134a3565b90509295989b9194979a5092959850565b6000806020838503121561398c57600080fd5b823567ffffffffffffffff808211156139a457600080fd5b818501915085601f8301126139b857600080fd5b8135818111156139c757600080fd5b8660208260051b85010111156139dc57600080fd5b60209290920196919550909350505050565b60005b83811015613a095781810151838201526020016139f1565b838111156117035750506000910152565b60008151808452613a328160208601602086016139ee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613ad7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613ac5858351613a1a565b94509285019290850190600101613a8b565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613b0457600080fd5b613b0d8b6135f2565b9950613b1b60208c016135f2565b9850613b2960408c016135f2565b975060608b0135965060808b01359550613b4560a08c01613811565b9450613b5360c08c01613811565b9350613b6160e08c016134a3565b9250613b706101008c016134a3565b91506101208b013567ffffffffffffffff811115613b8d57600080fd5b613b998d828e01613587565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bc557613bc56134bc565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0257600080fd5b8135613c106135a882613bab565b818152846020838601011115613c2557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c5857600080fd5b613c61856135f2565b9350613c6f60208601613811565b9250613c7d604086016134a3565b9150606085013567ffffffffffffffff811115613c9957600080fd5b613ca587828801613bf1565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cd457600080fd5b613cdd8d6135f2565b9b50613ceb60208e016135f2565b9a50613cf960408e016135f2565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d2360e08e01613811565b9450613d326101008e01613811565b9350613d416101208e01613811565b9250613d506101408e016134a3565b915067ffffffffffffffff6101608e01351115613d6c57600080fd5b613d7d8e6101608f01358f01613bf1565b90509295989b509295989b509295989b565b600060208284031215613da157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613df457613df4613da8565b039392505050565b600063ffffffff808316818516808303821115613e1b57613e1b613da8565b01949350505050565b600063ffffffff808316818103613e3d57613e3d613da8565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613eab57600080fd5b83018035915067ffffffffffffffff821115613ec657600080fd5b60200191503681900382131561308b57600080fd5b8183823760009101908152919050565b600060208284031215613efd57600080fd5b815167ffffffffffffffff811115613f1457600080fd5b8201601f81018413613f2557600080fd5b8051613f336135a882613bab565b818152856020838501011115613f4857600080fd5b61243c8260208301602086016139ee565b6020815260006128b86020830184613a1a565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9d57613f9d613da8565b5060010190565b67ffffffffffffffff831681526040602082015260006128b56040830184613a1a565b600081518084526020808501945080840160005b83811015613ff757815187529582019590820190600101613fdb565b509495945050505050565b600081518084526020808501945080840160005b83811015613ff757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614016565b85815260a06020820152600061406160a0830187613fc7565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140908287614002565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411b60c084018267ffffffffffffffff169052565b5060e083015161413760e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1b57613e1b613da8565b60008282101561418257614182613da8565b500390565b6000821982111561419a5761419a613da8565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141cf60e0840182613fc7565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261243c8282614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826142785761427861423a565b500490565b60008261428c5761428c61423a565b500690565b6000602082840312156142a357600080fd5b81516128b8816137a8565b600067ffffffffffffffff83811690831681811015613df457613df4613da8565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430757614307613da8565b500290565b6000825161431e8184602087016139ee565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220355f32bdb028a28cbe50e81ac06a0ec2427ffb0f4e0b67010c2cd12bb9b1455664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b50610245610240366004613678565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613774565b6106b0565b3480156102a057600080fd5b506102456102af36600461378f565b61073d565b3480156102c057600080fd5b506102456102cf3660046137b6565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137f6565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b610245610325366004613829565b610ab1565b34801561033657600080fd5b5061024561034536600461388f565b610f28565b34801561035657600080fd5b506103856103653660046138b1565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138db565b6110cf565b34801561044d57600080fd5b5061024561045c36600461378f565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e6366004613979565b6112ff565b60405161021c9190613a64565b34801561050457600080fd5b50610245610513366004613ae4565b6114d9565b34801561052457600080fd5b50610245610533366004613774565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c42565b6115ab565b34801561059157600080fd5b506105a56105a036600461378f565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d536600461378f565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613774565b611737565b34801561061357600080fd5b50610245610622366004613cb1565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611e17565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e98565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611e17565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611e17565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d8f565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dd7565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613dfc565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f84565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612060565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e24565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611e17565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120f1565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612168565b905060006111c782848b886000612198565b90506111d882828a88876000612445565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611e17565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e47565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134bc565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e47565b90506020028101906113eb9190613e76565b6040516113f9929190613edb565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613eeb565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b808484815181106114b2576114b2613e47565b6020026020010181905250505080806114ca90613f6c565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61257a565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611e17565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126f9565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127e5565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613fa4565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120f1565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127e5565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612168565b9050600061196982848d896000612198565b905061197a82828c89876000612445565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e47565b90600052602060002090600302019050611b6d81600101548484612882565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128bf565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff16612900565b60408301515160005b8163ffffffff168163ffffffff161015611d1157600085604001518263ffffffff1681518110611ca357611ca3613e47565b602002602001015190506000811115611d0857611d088660a001518363ffffffff1681518110611cd557611cd5613e47565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50600101611c71565b50835115611daa57611d2284612994565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611da192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611e08959493929190614048565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a38565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008160405160200161217b91906140a6565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121d057506706f05b59d3b200008560c0015167ffffffffffffffff16105b612236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106122b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122c15750600061243c565b6122da84848760c001516122d5919061414d565b612b44565b600087815260056020526040812054606088015192935086926122fd9190614170565b9050828110156123265780925061232383868960c0015161231e919061414d565b612b7e565b91505b60008881526005602052604081208054859290612344908490614187565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123cc57836123b95760408701516123b99073ffffffffffffffffffffffffffffffffffffffff16333085611f84565b6123c7876020015183612ba7565b612439565b83612406576123c7338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f84909392919063ffffffff16565b612439876020015183896040015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f60405161256a9c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264f60038463ffffffff168154811061263657612636613e47565b9060005260206000209060030201600001548284612ce8565b6126b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126c082612168565b905060006126d78284856060015160006001612198565b90506126e98282600080876001612445565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286c82612d00565b9050612879878285612d3b565b50505050505050565b60006128b582858560405160200161289a919061419f565b60405160208183030381529060405280519060200120612dd9565b90505b9392505050565b6000806128ce61010084614269565b905060006128de6101008561427d565b6000928352602095909552506040902054600190931b92831690921492915050565b600061290e61010083614269565b9050600061291e6101008461427d565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fde565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614291565b6000612a9a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612def9092919063ffffffff16565b8051909150156106ab5780806020019051810190612ab89190614291565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b5882670de0b6b3a76400006142ae565b67ffffffffffffffff16612b7484670de0b6b3a76400006142cf565b6128b89190614269565b6000670de0b6b3a7640000612b9383826142ae565b612b749067ffffffffffffffff16856142cf565b73ffffffffffffffffffffffffffffffffffffffff82163b15612c055761103e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838361293e565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8d57600080fd5b505af1158015612ca1573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128b582858560405160200161289a91906140a6565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161217b565b612d458282612dfe565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612de68584612e22565b14949350505050565b60606128b58484600085612e8e565b6000806000612e0d8585613024565b91509150612e1a81613092565b509392505050565b600081815b8451811015612e1a576000858281518110612e4457612e44613e47565b60200260200101519050808311612e6a5760008381526020829052604090209250612e7b565b600081815260208490526040902092505b5080612e8681613f6c565b915050612e27565b606082471015612f20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fc7919061430c565b60006040518083038185875af1925050503d8060008114613004576040519150601f19603f3d011682016040523d82523d6000602084013e613009565b606091505b50915091506130198282866132e6565b979650505050505050565b600080825160410361305a5760208301516040840151606085015160001a61304e87828585613339565b9450945050505061308b565b82516040036130835760208301516040840151613078868383613451565b93509350505061308b565b506000905060025b9250929050565b60008160048111156130a6576130a6614328565b036130ae5750565b60018160048111156130c2576130c2614328565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b600281600481111561313d5761313d614328565b036131a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131b8576131b8614328565b03613245576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561325957613259614328565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132f55750816128b8565b8251156133055782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156133705750600090506003613448565b8460ff16601b1415801561338857508460ff16601c14155b156133995750600090506004613448565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133ed573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661344157600060019250925050613448565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161348760ff86901c601b614187565b905061349587828885613339565b935093505050935093915050565b803563ffffffff811681146134b757600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561350e5761350e6134bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561355b5761355b6134bc565b604052919050565b600067ffffffffffffffff82111561357d5761357d6134bc565b5060051b60200190565b600082601f83011261359857600080fd5b813560206135ad6135a883613563565b613514565b82815260059290921b840181019181810190868411156135cc57600080fd5b8286015b848110156135e757803583529183019183016135d0565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134b757600080fd5b600082601f83011261362757600080fd5b813560206136376135a883613563565b82815260059290921b8401810191818101908684111561365657600080fd5b8286015b848110156135e75761366b816135f2565b835291830191830161365a565b60008060006060848603121561368d57600080fd5b613696846134a3565b9250602084013567ffffffffffffffff808211156136b357600080fd5b9085019060c082880312156136c757600080fd5b6136cf6134eb565b82358152602083013560208201526040830135828111156136ef57600080fd5b6136fb89828601613587565b60408301525061370d606084016134a3565b606082015261371e608084016135f2565b608082015260a08301358281111561373557600080fd5b61374189828601613616565b60a0830152509350604086013591508082111561375d57600080fd5b5061376a86828701613587565b9150509250925092565b60006020828403121561378657600080fd5b6128b8826135f2565b6000602082840312156137a157600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137cb57600080fd5b6137d4846135f2565b92506020840135915060408401356137eb816137a8565b809150509250925092565b60006020828403121561380857600080fd5b6128b8826134a3565b803567ffffffffffffffff811681146134b757600080fd5b60008060008060008060c0878903121561384257600080fd5b61384b876135f2565b9550613859602088016135f2565b9450604087013593506060870135925061387560808801613811565b915061388360a088016134a3565b90509295509295509295565b600080604083850312156138a257600080fd5b50508035926020909101359150565b600080604083850312156138c457600080fd5b6138cd836135f2565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138fb57600080fd5b6139048b6135f2565b995061391260208c016135f2565b985061392060408c016135f2565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061394a60e08c01613811565b92506139596101008c01613811565b91506139686101208c016134a3565b90509295989b9194979a5092959850565b6000806020838503121561398c57600080fd5b823567ffffffffffffffff808211156139a457600080fd5b818501915085601f8301126139b857600080fd5b8135818111156139c757600080fd5b8660208260051b85010111156139dc57600080fd5b60209290920196919550909350505050565b60005b83811015613a095781810151838201526020016139f1565b838111156117035750506000910152565b60008151808452613a328160208601602086016139ee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613ad7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613ac5858351613a1a565b94509285019290850190600101613a8b565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613b0457600080fd5b613b0d8b6135f2565b9950613b1b60208c016135f2565b9850613b2960408c016135f2565b975060608b0135965060808b01359550613b4560a08c01613811565b9450613b5360c08c01613811565b9350613b6160e08c016134a3565b9250613b706101008c016134a3565b91506101208b013567ffffffffffffffff811115613b8d57600080fd5b613b998d828e01613587565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bc557613bc56134bc565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0257600080fd5b8135613c106135a882613bab565b818152846020838601011115613c2557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c5857600080fd5b613c61856135f2565b9350613c6f60208601613811565b9250613c7d604086016134a3565b9150606085013567ffffffffffffffff811115613c9957600080fd5b613ca587828801613bf1565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cd457600080fd5b613cdd8d6135f2565b9b50613ceb60208e016135f2565b9a50613cf960408e016135f2565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d2360e08e01613811565b9450613d326101008e01613811565b9350613d416101208e01613811565b9250613d506101408e016134a3565b915067ffffffffffffffff6101608e01351115613d6c57600080fd5b613d7d8e6101608f01358f01613bf1565b90509295989b509295989b509295989b565b600060208284031215613da157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613df457613df4613da8565b039392505050565b600063ffffffff808316818516808303821115613e1b57613e1b613da8565b01949350505050565b600063ffffffff808316818103613e3d57613e3d613da8565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613eab57600080fd5b83018035915067ffffffffffffffff821115613ec657600080fd5b60200191503681900382131561308b57600080fd5b8183823760009101908152919050565b600060208284031215613efd57600080fd5b815167ffffffffffffffff811115613f1457600080fd5b8201601f81018413613f2557600080fd5b8051613f336135a882613bab565b818152856020838501011115613f4857600080fd5b61243c8260208301602086016139ee565b6020815260006128b86020830184613a1a565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9d57613f9d613da8565b5060010190565b67ffffffffffffffff831681526040602082015260006128b56040830184613a1a565b600081518084526020808501945080840160005b83811015613ff757815187529582019590820190600101613fdb565b509495945050505050565b600081518084526020808501945080840160005b83811015613ff757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614016565b85815260a06020820152600061406160a0830187613fc7565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140908287614002565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411b60c084018267ffffffffffffffff169052565b5060e083015161413760e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1b57613e1b613da8565b60008282101561418257614182613da8565b500390565b6000821982111561419a5761419a613da8565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141cf60e0840182613fc7565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261243c8282614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826142785761427861423a565b500490565b60008261428c5761428c61423a565b500690565b6000602082840312156142a357600080fd5b81516128b8816137a8565b600067ffffffffffffffff83811690831681811015613df457613df4613da8565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430757614307613da8565b500290565b6000825161431e8184602087016139ee565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220355f32bdb028a28cbe50e81ac06a0ec2427ffb0f4e0b67010c2cd12bb9b1455664736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/LpTokenFactory.json b/deployments/rinkeby/LpTokenFactory.json index 1bd08ca1..42678ffd 100644 --- a/deployments/rinkeby/LpTokenFactory.json +++ b/deployments/rinkeby/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _append(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _append(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _append(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x3af40092646f132fcdba4c42b51359abcd3797e5084fad627dd27ba47e0ca9c9\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _append(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _append(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _append(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x3af40092646f132fcdba4c42b51359abcd3797e5084fad627dd27ba47e0ca9c9\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212209d0b7b3b71c235b34e79d5b72791522522cbfce906136557bf267400633999a264736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212209d0b7b3b71c235b34e79d5b72791522522cbfce906136557bf267400633999a264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Optimism_Adapter.json b/deployments/rinkeby/Optimism_Adapter.json index 6f432d09..fe050961 100644 --- a/deployments/rinkeby/Optimism_Adapter.json +++ b/deployments/rinkeby/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"OVM_XCHAIN: messenger contract unauthenticated\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0xb9a90934f8e09dd581cb65fa9d2f7904bfcb0dfe86f45a8b31d0b3037a1facd3\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 5_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Optimism.\\n * @param target Contract on Optimism that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Optimism.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d38de11bc73db08f7406261d9b64b2985faa06cbd48aa8cc28042efd284e4d9\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"OVM_XCHAIN: messenger contract unauthenticated\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0xb9a90934f8e09dd581cb65fa9d2f7904bfcb0dfe86f45a8b31d0b3037a1facd3\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 5_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Optimism.\\n * @param target Contract on Optimism that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Optimism.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d38de11bc73db08f7406261d9b64b2985faa06cbd48aa8cc28042efd284e4d9\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052624c4b4060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161117138038061117183398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f9c6101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108c60152610f9c6000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c77565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610cf3565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff8616828561074e565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610711827f000000000000000000000000000000000000000000000000000000000000000083610889565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610742929190610e49565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190610e78565b6107f39190610e91565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610883908590610936565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b906108ff90869085908790600401610ed0565b600060405180830381600087803b15801561091957600080fd5b505af115801561092d573d6000803e3d6000fd5b50505050505050565b6000610998826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4c9092919063ffffffff16565b805190915015610a4757808060200190518101906109b69190610f15565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a5b8484600085610a65565b90505b9392505050565b606082471015610af7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3e565b73ffffffffffffffffffffffffffffffffffffffff85163b610b75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b9e9190610f37565b60006040518083038185875af1925050503d8060008114610bdb576040519150601f19603f3d011682016040523d82523d6000602084013e610be0565b606091505b5091509150610bf0828286610bfb565b979650505050505050565b60608315610c0a575081610a5e565b825115610c1a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e9190610f53565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7257600080fd5b919050565b60008060008060808587031215610c8d57600080fd5b610c9685610c4e565b9350610ca460208601610c4e565b925060408501359150610cb960608601610c4e565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0657600080fd5b610d0f83610c4e565b9150602083013567ffffffffffffffff80821115610d2c57600080fd5b818501915085601f830112610d4057600080fd5b813581811115610d5257610d52610cc4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9857610d98610cc4565b81604052828152886020848701011115610db157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610dee578181015183820152602001610dd6565b838111156108835750506000910152565b60008151808452610e17816020860160208601610dd3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5b6040830184610dff565b600060208284031215610e8a57600080fd5b5051919050565b60008219821115610ecb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000610eff6060830185610dff565b905063ffffffff83166040830152949350505050565b600060208284031215610f2757600080fd5b81518015158114610a5e57600080fd5b60008251610f49818460208701610dd3565b9190910192915050565b602081526000610a5e6020830184610dff56fea2646970667358221220b439c41917b515109464c40d4dc8343a6f6e68157bca87353f5213176038c50a64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c77565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610cf3565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff8616828561074e565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610711827f000000000000000000000000000000000000000000000000000000000000000083610889565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610742929190610e49565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190610e78565b6107f39190610e91565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610883908590610936565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b906108ff90869085908790600401610ed0565b600060405180830381600087803b15801561091957600080fd5b505af115801561092d573d6000803e3d6000fd5b50505050505050565b6000610998826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4c9092919063ffffffff16565b805190915015610a4757808060200190518101906109b69190610f15565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a5b8484600085610a65565b90505b9392505050565b606082471015610af7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3e565b73ffffffffffffffffffffffffffffffffffffffff85163b610b75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b9e9190610f37565b60006040518083038185875af1925050503d8060008114610bdb576040519150601f19603f3d011682016040523d82523d6000602084013e610be0565b606091505b5091509150610bf0828286610bfb565b979650505050505050565b60608315610c0a575081610a5e565b825115610c1a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e9190610f53565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7257600080fd5b919050565b60008060008060808587031215610c8d57600080fd5b610c9685610c4e565b9350610ca460208601610c4e565b925060408501359150610cb960608601610c4e565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0657600080fd5b610d0f83610c4e565b9150602083013567ffffffffffffffff80821115610d2c57600080fd5b818501915085601f830112610d4057600080fd5b813581811115610d5257610d52610cc4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9857610d98610cc4565b81604052828152886020848701011115610db157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610dee578181015183820152602001610dd6565b838111156108835750506000910152565b60008151808452610e17816020860160208601610dd3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5b6040830184610dff565b600060208284031215610e8a57600080fd5b5051919050565b60008219821115610ecb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000610eff6060830185610dff565b905063ffffffff83166040830152949350505050565b600060208284031215610f2757600080fd5b81518015158114610a5e57600080fd5b60008251610f49818460208701610dd3565b9190910192915050565b602081526000610a5e6020830184610dff56fea2646970667358221220b439c41917b515109464c40d4dc8343a6f6e68157bca87353f5213176038c50a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/PolygonTokenBridger.json b/deployments/rinkeby/PolygonTokenBridger.json index b560d73e..d2052b71 100644 --- a/deployments/rinkeby/PolygonTokenBridger.json +++ b/deployments/rinkeby/PolygonTokenBridger.json @@ -116,7 +116,7 @@ "args": ["0xa1b6DA4AaE90fA16F3A3338c8d1Dc70B4926FCa7", "0xc778417E063141139Fce010982780140Aa0cD5Ab"], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWrappedMatic\",\"type\":\"bool\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1Weth\":\"Ethereum WETH address.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256,bool)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"isWrappedMatic\":\"True if token is WMATIC.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256,bool)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\ninterface PolygonIERC20 is IERC20 {\\n function withdraw(uint256 amount) external;\\n}\\n\\ninterface MaticToken {\\n function withdraw(uint256 amount) external payable;\\n}\\n\\n/**\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\n * mechanism from normal create.\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\n * sender.\\n */\\ncontract PolygonTokenBridger is Lockable {\\n using SafeERC20 for PolygonIERC20;\\n using SafeERC20 for IERC20;\\n\\n // Gas token for Polygon.\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\n\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\n address public immutable destination;\\n\\n // WETH contract on Ethereum.\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs Token Bridger contract.\\n * @param _destination Where to send tokens to for this network.\\n * @param _l1Weth Ethereum WETH address.\\n */\\n constructor(address _destination, WETH9 _l1Weth) {\\n destination = _destination;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\n * @notice The caller of this function must approve this contract to spend amount of token.\\n * @param token Token to bridge.\\n * @param amount Amount to bridge.\\n * @param isWrappedMatic True if token is WMATIC.\\n */\\n function send(\\n PolygonIERC20 token,\\n uint256 amount,\\n bool isWrappedMatic\\n ) public nonReentrant {\\n token.safeTransferFrom(msg.sender, address(this), amount);\\n\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\n token.withdraw(amount);\\n\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\\n }\\n\\n /**\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\n * @param token Token to send to destination.\\n */\\n function retrieve(IERC20 token) public nonReentrant {\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\n }\\n\\n receive() external payable {\\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\\n }\\n}\\n\",\"keccak256\":\"0x79b3a0f440bf429abcb41d4d808892d0bd73e890334585f3ab1dd67a2bbe32cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWrappedMatic\",\"type\":\"bool\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1Weth\":\"Ethereum WETH address.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256,bool)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"isWrappedMatic\":\"True if token is WMATIC.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256,bool)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\ninterface PolygonIERC20 is IERC20 {\\n function withdraw(uint256 amount) external;\\n}\\n\\ninterface MaticToken {\\n function withdraw(uint256 amount) external payable;\\n}\\n\\n/**\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\n * mechanism from normal create.\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\n * sender.\\n */\\ncontract PolygonTokenBridger is Lockable {\\n using SafeERC20 for PolygonIERC20;\\n using SafeERC20 for IERC20;\\n\\n // Gas token for Polygon.\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\n\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\n address public immutable destination;\\n\\n // WETH contract on Ethereum.\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs Token Bridger contract.\\n * @param _destination Where to send tokens to for this network.\\n * @param _l1Weth Ethereum WETH address.\\n */\\n constructor(address _destination, WETH9 _l1Weth) {\\n destination = _destination;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\n * @notice The caller of this function must approve this contract to spend amount of token.\\n * @param token Token to bridge.\\n * @param amount Amount to bridge.\\n * @param isWrappedMatic True if token is WMATIC.\\n */\\n function send(\\n PolygonIERC20 token,\\n uint256 amount,\\n bool isWrappedMatic\\n ) public nonReentrant {\\n token.safeTransferFrom(msg.sender, address(this), amount);\\n\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\n token.withdraw(amount);\\n\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\\n }\\n\\n /**\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\n * @param token Token to send to destination.\\n */\\n function retrieve(IERC20 token) public nonReentrant {\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\n }\\n\\n receive() external payable {\\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\\n }\\n}\\n\",\"keccak256\":\"0x79b3a0f440bf429abcb41d4d808892d0bd73e890334585f3ab1dd67a2bbe32cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405234801561001057600080fd5b50604051610bbd380380610bbd83398101604081905261002f9161006b565b6000805460ff191660011790556001600160a01b039182166080521660a0526100a5565b6001600160a01b038116811461006857600080fd5b50565b6000806040838503121561007e57600080fd5b825161008981610053565b602084015190925061009a81610053565b809150509250929050565b60805160a051610ae66100d7600039600081816070015261012901526000818161018601526102450152610ae66000f3fe60806040526004361061005e5760003560e01c8063b269681d11610043578063b269681d14610174578063d124dc4f146101a8578063dc354296146101c857600080fd5b80630a79309b146100f7578063146bf4b11461011757600080fd5b366100f25760005460ff16156100f0577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156100d657600080fd5b505af11580156100ea573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561010357600080fd5b506100f0610112366004610974565b6101de565b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561018057600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101b457600080fd5b506100f06101c336600461099f565b610318565b3480156101d457600080fd5b5061014b61101081565b6101e6610499565b610213600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526102e5907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c791906109e1565b73ffffffffffffffffffffffffffffffffffffffff8416919061050c565b610315600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b610320610499565b61034d600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61036f73ffffffffffffffffffffffffffffffffffffffff84163330856105e0565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d90602401600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b505050508015610464576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905261101090632e1a7d4d9084906024016000604051808303818588803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b50505050505b610494600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b505050565b60005460ff1661050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104949084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610644565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261063e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161055e565b50505050565b60006106a6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107509092919063ffffffff16565b80519091501561049457808060200190518101906106c491906109fa565b610494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610501565b606061075f8484600085610769565b90505b9392505050565b6060824710156107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610501565b73ffffffffffffffffffffffffffffffffffffffff85163b610879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610501565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108a29190610a43565b60006040518083038185875af1925050503d80600081146108df576040519150601f19603f3d011682016040523d82523d6000602084013e6108e4565b606091505b50915091506108f48282866108ff565b979650505050505050565b6060831561090e575081610762565b82511561091e5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105019190610a5f565b73ffffffffffffffffffffffffffffffffffffffff8116811461031557600080fd5b60006020828403121561098657600080fd5b813561076281610952565b801515811461031557600080fd5b6000806000606084860312156109b457600080fd5b83356109bf81610952565b92506020840135915060408401356109d681610991565b809150509250925092565b6000602082840312156109f357600080fd5b5051919050565b600060208284031215610a0c57600080fd5b815161076281610991565b60005b83811015610a32578181015183820152602001610a1a565b8381111561063e5750506000910152565b60008251610a55818460208701610a17565b9190910192915050565b6020815260008251806020840152610a7e816040850160208701610a17565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220a6bfbc7a1aefd28bea6fd266df05752c1c618d43ebe6b51f137c909303fc674f64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061005e5760003560e01c8063b269681d11610043578063b269681d14610174578063d124dc4f146101a8578063dc354296146101c857600080fd5b80630a79309b146100f7578063146bf4b11461011757600080fd5b366100f25760005460ff16156100f0577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156100d657600080fd5b505af11580156100ea573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561010357600080fd5b506100f0610112366004610974565b6101de565b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561018057600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101b457600080fd5b506100f06101c336600461099f565b610318565b3480156101d457600080fd5b5061014b61101081565b6101e6610499565b610213600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526102e5907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c791906109e1565b73ffffffffffffffffffffffffffffffffffffffff8416919061050c565b610315600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b610320610499565b61034d600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61036f73ffffffffffffffffffffffffffffffffffffffff84163330856105e0565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d90602401600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b505050508015610464576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905261101090632e1a7d4d9084906024016000604051808303818588803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b50505050505b610494600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b505050565b60005460ff1661050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104949084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610644565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261063e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161055e565b50505050565b60006106a6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107509092919063ffffffff16565b80519091501561049457808060200190518101906106c491906109fa565b610494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610501565b606061075f8484600085610769565b90505b9392505050565b6060824710156107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610501565b73ffffffffffffffffffffffffffffffffffffffff85163b610879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610501565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108a29190610a43565b60006040518083038185875af1925050503d80600081146108df576040519150601f19603f3d011682016040523d82523d6000602084013e6108e4565b606091505b50915091506108f48282866108ff565b979650505050505050565b6060831561090e575081610762565b82511561091e5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105019190610a5f565b73ffffffffffffffffffffffffffffffffffffffff8116811461031557600080fd5b60006020828403121561098657600080fd5b813561076281610952565b801515811461031557600080fd5b6000806000606084860312156109b457600080fd5b83356109bf81610952565b92506020840135915060408401356109d681610991565b809150509250925092565b6000602082840312156109f357600080fd5b5051919050565b600060208284031215610a0c57600080fd5b815161076281610991565b60005b83811015610a32578181015183820152602001610a1a565b8381111561063e5750506000910152565b60008251610a55818460208701610a17565b9190910192915050565b6020815260008251806020840152610a7e816040850160208701610a17565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220a6bfbc7a1aefd28bea6fd266df05752c1c618d43ebe6b51f137c909303fc674f64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Polygon_Adapter.json b/deployments/rinkeby/Polygon_Adapter.json index 81af2414..f3d8cf1a 100644 --- a/deployments/rinkeby/Polygon_Adapter.json +++ b/deployments/rinkeby/Polygon_Adapter.json @@ -181,7 +181,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_fxStateSender\":\"FxStateSender Polygon system helper contract.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system helper contract.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface IRootChainManager {\\n function depositEtherFor(address user) external payable;\\n\\n function depositFor(\\n address user,\\n address rootToken,\\n bytes calldata depositData\\n ) external;\\n}\\n\\ninterface IFxStateSender {\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\n}\\n\\n/**\\n * @notice Sends cross chain messages Polygon L2 network.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Polygon_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n IRootChainManager public immutable rootChainManager;\\n IFxStateSender public immutable fxStateSender;\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _rootChainManager RootChainManager Polygon system helper contract.\\n * @param _fxStateSender FxStateSender Polygon system helper contract.\\n * @param _l1Weth WETH address on L1.\\n */\\n constructor(\\n IRootChainManager _rootChainManager,\\n IFxStateSender _fxStateSender,\\n WETH9 _l1Weth\\n ) {\\n rootChainManager = _rootChainManager;\\n fxStateSender = _fxStateSender;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Polygon.\\n * @param target Contract on Polygon that will receive message.\\n * @param message Data to send to target.\\n */\\n\\n function relayMessage(address target, bytes memory message) external payable override {\\n fxStateSender.sendMessageToChild(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Polygon.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n rootChainManager.depositEtherFor{ value: amount }(to);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d47c68dbc8612ab9959918f1d085461bc6765e033efad68e95f2ae4e2441cf6\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_fxStateSender\":\"FxStateSender Polygon system helper contract.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system helper contract.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface IRootChainManager {\\n function depositEtherFor(address user) external payable;\\n\\n function depositFor(\\n address user,\\n address rootToken,\\n bytes calldata depositData\\n ) external;\\n}\\n\\ninterface IFxStateSender {\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\n}\\n\\n/**\\n * @notice Sends cross chain messages Polygon L2 network.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Polygon_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n IRootChainManager public immutable rootChainManager;\\n IFxStateSender public immutable fxStateSender;\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _rootChainManager RootChainManager Polygon system helper contract.\\n * @param _fxStateSender FxStateSender Polygon system helper contract.\\n * @param _l1Weth WETH address on L1.\\n */\\n constructor(\\n IRootChainManager _rootChainManager,\\n IFxStateSender _fxStateSender,\\n WETH9 _l1Weth\\n ) {\\n rootChainManager = _rootChainManager;\\n fxStateSender = _fxStateSender;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Polygon.\\n * @param target Contract on Polygon that will receive message.\\n * @param message Data to send to target.\\n */\\n\\n function relayMessage(address target, bytes memory message) external payable override {\\n fxStateSender.sendMessageToChild(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Polygon.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n rootChainManager.depositEtherFor{ value: amount }(to);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d47c68dbc8612ab9959918f1d085461bc6765e033efad68e95f2ae4e2441cf6\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60e060405234801561001057600080fd5b50604051610dc7380380610dc783398101604081905261002f91610064565b6001600160a01b0392831660805290821660a0521660c0526100b1565b6001600160a01b038116811461006157600080fd5b50565b60008060006060848603121561007957600080fd5b83516100848161004c565b60208501519093506100958161004c565b60408501519092506100a68161004c565b809150509250925092565b60805160a05160c051610cbf6101086000396000818160710152818161014e01526101ce01526000818160e3015261047b0152600081816101170152818161028201528181610303015261032a0152610cbf6000f3fe60806040526004361061005a5760003560e01c8063a996cabb11610043578063a996cabb146100d1578063bd07018d14610105578063e6eb8ade1461013957600080fd5b8063146bf4b11461005f57806352c8c75c146100bc575b600080fd5b34801561006b57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100cf6100ca36600461099d565b61014c565b005b3480156100dd57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b34801561011157600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b6100cf610147366004610a19565b61043e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036102e7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561022757600080fd5b505af115801561023b573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b1580156102c957600080fd5b505af11580156102dd573d6000803e3d6000fd5b50505050506103d9565b61032873ffffffffffffffffffffffffffffffffffffffff85167f000000000000000000000000000000000000000000000000000000000000000084610521565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161037991815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016103a693929190610b6f565b600060405180830381600087803b1580156103c057600080fd5b505af11580156103d4573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906104b29085908590600401610bb1565b600060405180830381600087803b1580156104cc57600080fd5b505af11580156104e0573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610515929190610bb1565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190610be0565b6105c69190610bf9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061065690859061065c565b50505050565b60006106be826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107729092919063ffffffff16565b80519091501561076d57808060200190518101906106dc9190610c38565b61076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610781848460008561078b565b90505b9392505050565b60608247101561081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610764565b73ffffffffffffffffffffffffffffffffffffffff85163b61089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610764565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108c49190610c5a565b60006040518083038185875af1925050503d8060008114610901576040519150601f19603f3d011682016040523d82523d6000602084013e610906565b606091505b5091509150610916828286610921565b979650505050505050565b60608315610930575081610784565b8251156109405782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107649190610c76565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099857600080fd5b919050565b600080600080608085870312156109b357600080fd5b6109bc85610974565b93506109ca60208601610974565b9250604085013591506109df60608601610974565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610a2c57600080fd5b610a3583610974565b9150602083013567ffffffffffffffff80821115610a5257600080fd5b818501915085601f830112610a6657600080fd5b813581811115610a7857610a786109ea565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610abe57610abe6109ea565b81604052828152886020848701011115610ad757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610b14578181015183820152602001610afc565b838111156106565750506000910152565b60008151808452610b3d816020860160208601610af9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610ba86060830184610b25565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006107816040830184610b25565b600060208284031215610bf257600080fd5b5051919050565b60008219821115610c33577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610c4a57600080fd5b8151801515811461078457600080fd5b60008251610c6c818460208701610af9565b9190910192915050565b6020815260006107846020830184610b2556fea2646970667358221220314a1e3672715e1c9fd64c503fc29f347e18573590a2881a1f8a69e6e8bfabd264736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061005a5760003560e01c8063a996cabb11610043578063a996cabb146100d1578063bd07018d14610105578063e6eb8ade1461013957600080fd5b8063146bf4b11461005f57806352c8c75c146100bc575b600080fd5b34801561006b57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100cf6100ca36600461099d565b61014c565b005b3480156100dd57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b34801561011157600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b6100cf610147366004610a19565b61043e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036102e7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561022757600080fd5b505af115801561023b573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b1580156102c957600080fd5b505af11580156102dd573d6000803e3d6000fd5b50505050506103d9565b61032873ffffffffffffffffffffffffffffffffffffffff85167f000000000000000000000000000000000000000000000000000000000000000084610521565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161037991815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016103a693929190610b6f565b600060405180830381600087803b1580156103c057600080fd5b505af11580156103d4573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906104b29085908590600401610bb1565b600060405180830381600087803b1580156104cc57600080fd5b505af11580156104e0573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610515929190610bb1565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190610be0565b6105c69190610bf9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061065690859061065c565b50505050565b60006106be826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107729092919063ffffffff16565b80519091501561076d57808060200190518101906106dc9190610c38565b61076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610781848460008561078b565b90505b9392505050565b60608247101561081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610764565b73ffffffffffffffffffffffffffffffffffffffff85163b61089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610764565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108c49190610c5a565b60006040518083038185875af1925050503d8060008114610901576040519150601f19603f3d011682016040523d82523d6000602084013e610906565b606091505b5091509150610916828286610921565b979650505050505050565b60608315610930575081610784565b8251156109405782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107649190610c76565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099857600080fd5b919050565b600080600080608085870312156109b357600080fd5b6109bc85610974565b93506109ca60208601610974565b9250604085013591506109df60608601610974565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610a2c57600080fd5b610a3583610974565b9150602083013567ffffffffffffffff80821115610a5257600080fd5b818501915085601f830112610a6657600080fd5b813581811115610a7857610a786109ea565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610abe57610abe6109ea565b81604052828152886020848701011115610ad757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610b14578181015183820152602001610afc565b838111156106565750506000910152565b60008151808452610b3d816020860160208601610af9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610ba86060830184610b25565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006107816040830184610b25565b600060208284031215610bf257600080fd5b5051919050565b60008219821115610c33577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610c4a57600080fd5b8151801515811461078457600080fd5b60008251610c6c818460208701610af9565b9190910192915050565b6020815260006107846020830184610b2556fea2646970667358221220314a1e3672715e1c9fd64c503fc29f347e18573590a2881a1f8a69e6e8bfabd264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/RateModelStore.json b/deployments/rinkeby/RateModelStore.json index 6f142271..f00e55f5 100644 --- a/deployments/rinkeby/RateModelStore.json +++ b/deployments/rinkeby/RateModelStore.json @@ -163,7 +163,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "1bf8793c065ccb196e5a60f53c731ca8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"UpdatedRateModel\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenRateModels\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"updateRateModel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust the structure in the future.\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateRateModel(address,string)\":{\"params\":{\"l1Token\":\"the l1 token rate model to update.\",\"rateModel\":\"the updated rate model.\"}}},\"title\":\"Maps rate model objects to L1 token.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateRateModel(address,string)\":{\"notice\":\"Updates rate model string for L1 token.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RateModelStore.sol\":\"RateModelStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/RateModelStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Maps rate model objects to L1 token.\\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\\n * the structure in the future.\\n */\\ncontract RateModelStore is Ownable, MultiCaller {\\n mapping(address => string) public l1TokenRateModels;\\n\\n event UpdatedRateModel(address indexed l1Token, string rateModel);\\n\\n /**\\n * @notice Updates rate model string for L1 token.\\n * @param l1Token the l1 token rate model to update.\\n * @param rateModel the updated rate model.\\n */\\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\\n l1TokenRateModels[l1Token] = rateModel;\\n emit UpdatedRateModel(l1Token, rateModel);\\n }\\n}\\n\",\"keccak256\":\"0xa476c6f657c69316a86ceddbbffb29e77d6550598a3946db43970b9493aa0b16\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"UpdatedRateModel\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenRateModels\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"updateRateModel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust the structure in the future.\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateRateModel(address,string)\":{\"params\":{\"l1Token\":\"the l1 token rate model to update.\",\"rateModel\":\"the updated rate model.\"}}},\"title\":\"Maps rate model objects to L1 token.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateRateModel(address,string)\":{\"notice\":\"Updates rate model string for L1 token.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RateModelStore.sol\":\"RateModelStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/RateModelStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Maps rate model objects to L1 token.\\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\\n * the structure in the future.\\n */\\ncontract RateModelStore is Ownable, MultiCaller {\\n mapping(address => string) public l1TokenRateModels;\\n\\n event UpdatedRateModel(address indexed l1Token, string rateModel);\\n\\n /**\\n * @notice Updates rate model string for L1 token.\\n * @param l1Token the l1 token rate model to update.\\n * @param rateModel the updated rate model.\\n */\\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\\n l1TokenRateModels[l1Token] = rateModel;\\n emit UpdatedRateModel(l1Token, rateModel);\\n }\\n}\\n\",\"keccak256\":\"0xa476c6f657c69316a86ceddbbffb29e77d6550598a3946db43970b9493aa0b16\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cc68061007e6000396000f3fe6080604052600436106100655760003560e01c80638da5cb5b116100435780638da5cb5b146100d7578063ac9650d81461010c578063f2fde38b1461012c57600080fd5b80630be5512b1461006a578063715018a61461008c57806374cc3f3e146100a1575b600080fd5b34801561007657600080fd5b5061008a610085366004610887565b61014c565b005b34801561009857600080fd5b5061008a61025b565b3480156100ad57600080fd5b506100c16100bc366004610918565b6102e8565b6040516100ce91906109b4565b60405180910390f35b3480156100e357600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ce565b61011f61011a3660046109c7565b610382565b6040516100ce9190610a3c565b34801561013857600080fd5b5061008a610147366004610918565b61055c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160209081526040909120825161020892840190610701565b508173ffffffffffffffffffffffffffffffffffffffff167fffbed0e73ca0e16b79488dd92e2cea865dd04b08d41dd27f05abbad9584581388260405161024f91906109b4565b60405180910390a25050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b6102e6600061068c565b565b6001602052600090815260409020805461030190610abc565b80601f016020809104026020016040519081016040528092919081815260200182805461032d90610abc565b801561037a5780601f1061034f5761010080835404028352916020019161037a565b820191906000526020600020905b81548152906001019060200180831161035d57829003601f168201915b505050505081565b606034156103ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016101c9565b8167ffffffffffffffff811115610405576104056107c3565b60405190808252806020026020018201604052801561043857816020015b60608152602001906001900390816104235790505b50905060005b82811015610555576000803086868581811061045c5761045c610b0f565b905060200281019061046e9190610b3e565b60405161047c929190610baa565b600060405180830381855af49150503d80600081146104b7576040519150601f19603f3d011682016040523d82523d6000602084013e6104bc565b606091505b509150915081610522576044815110156104d557600080fd5b600481019050808060200190518101906104ef9190610bba565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c991906109b4565b8084848151811061053557610535610b0f565b60200260200101819052505050808061054d90610c31565b91505061043e565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b73ffffffffffffffffffffffffffffffffffffffff8116610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c9565b6106898161068c565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461070d90610abc565b90600052602060002090601f01602090048101928261072f5760008555610775565b82601f1061074857805160ff1916838001178555610775565b82800160010185558215610775579182015b8281111561077557825182559160200191906001019061075a565b50610781929150610785565b5090565b5b808211156107815760008155600101610786565b803573ffffffffffffffffffffffffffffffffffffffff811681146107be57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610839576108396107c3565b604052919050565b600067ffffffffffffffff82111561085b5761085b6107c3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561089a57600080fd5b6108a38361079a565b9150602083013567ffffffffffffffff8111156108bf57600080fd5b8301601f810185136108d057600080fd5b80356108e36108de82610841565b6107f2565b8181528660208385010111156108f857600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561092a57600080fd5b6109338261079a565b9392505050565b60005b8381101561095557818101518382015260200161093d565b83811115610964576000848401525b50505050565b6000815180845261098281602086016020860161093a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610933602083018461096a565b600080602083850312156109da57600080fd5b823567ffffffffffffffff808211156109f257600080fd5b818501915085601f830112610a0657600080fd5b813581811115610a1557600080fd5b8660208260051b8501011115610a2a57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610aaf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610a9d85835161096a565b94509285019290850190600101610a63565b5092979650505050505050565b600181811c90821680610ad057607f821691505b602082108103610b09577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b7357600080fd5b83018035915067ffffffffffffffff821115610b8e57600080fd5b602001915036819003821315610ba357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610bcc57600080fd5b815167ffffffffffffffff811115610be357600080fd5b8201601f81018413610bf457600080fd5b8051610c026108de82610841565b818152856020838501011115610c1757600080fd5b610c2882602083016020860161093a565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c89577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea26469706673582212208e5db8f43ebedc8eed583769234122bc8473aea877b1a57cffaf607e81f67c7b64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100655760003560e01c80638da5cb5b116100435780638da5cb5b146100d7578063ac9650d81461010c578063f2fde38b1461012c57600080fd5b80630be5512b1461006a578063715018a61461008c57806374cc3f3e146100a1575b600080fd5b34801561007657600080fd5b5061008a610085366004610887565b61014c565b005b34801561009857600080fd5b5061008a61025b565b3480156100ad57600080fd5b506100c16100bc366004610918565b6102e8565b6040516100ce91906109b4565b60405180910390f35b3480156100e357600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ce565b61011f61011a3660046109c7565b610382565b6040516100ce9190610a3c565b34801561013857600080fd5b5061008a610147366004610918565b61055c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160209081526040909120825161020892840190610701565b508173ffffffffffffffffffffffffffffffffffffffff167fffbed0e73ca0e16b79488dd92e2cea865dd04b08d41dd27f05abbad9584581388260405161024f91906109b4565b60405180910390a25050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b6102e6600061068c565b565b6001602052600090815260409020805461030190610abc565b80601f016020809104026020016040519081016040528092919081815260200182805461032d90610abc565b801561037a5780601f1061034f5761010080835404028352916020019161037a565b820191906000526020600020905b81548152906001019060200180831161035d57829003601f168201915b505050505081565b606034156103ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016101c9565b8167ffffffffffffffff811115610405576104056107c3565b60405190808252806020026020018201604052801561043857816020015b60608152602001906001900390816104235790505b50905060005b82811015610555576000803086868581811061045c5761045c610b0f565b905060200281019061046e9190610b3e565b60405161047c929190610baa565b600060405180830381855af49150503d80600081146104b7576040519150601f19603f3d011682016040523d82523d6000602084013e6104bc565b606091505b509150915081610522576044815110156104d557600080fd5b600481019050808060200190518101906104ef9190610bba565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c991906109b4565b8084848151811061053557610535610b0f565b60200260200101819052505050808061054d90610c31565b91505061043e565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b73ffffffffffffffffffffffffffffffffffffffff8116610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c9565b6106898161068c565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461070d90610abc565b90600052602060002090601f01602090048101928261072f5760008555610775565b82601f1061074857805160ff1916838001178555610775565b82800160010185558215610775579182015b8281111561077557825182559160200191906001019061075a565b50610781929150610785565b5090565b5b808211156107815760008155600101610786565b803573ffffffffffffffffffffffffffffffffffffffff811681146107be57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610839576108396107c3565b604052919050565b600067ffffffffffffffff82111561085b5761085b6107c3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561089a57600080fd5b6108a38361079a565b9150602083013567ffffffffffffffff8111156108bf57600080fd5b8301601f810185136108d057600080fd5b80356108e36108de82610841565b6107f2565b8181528660208385010111156108f857600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561092a57600080fd5b6109338261079a565b9392505050565b60005b8381101561095557818101518382015260200161093d565b83811115610964576000848401525b50505050565b6000815180845261098281602086016020860161093a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610933602083018461096a565b600080602083850312156109da57600080fd5b823567ffffffffffffffff808211156109f257600080fd5b818501915085601f830112610a0657600080fd5b813581811115610a1557600080fd5b8660208260051b8501011115610a2a57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610aaf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610a9d85835161096a565b94509285019290850190600101610a63565b5092979650505050505050565b600181811c90821680610ad057607f821691505b602082108103610b09577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b7357600080fd5b83018035915067ffffffffffffffff821115610b8e57600080fd5b602001915036819003821315610ba357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610bcc57600080fd5b815167ffffffffffffffff811115610be357600080fd5b8201601f81018413610bf457600080fd5b8051610c026108de82610841565b818152856020838501011115610c1757600080fd5b610c2882602083016020860161093a565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c89577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea26469706673582212208e5db8f43ebedc8eed583769234122bc8473aea877b1a57cffaf607e81f67c7b64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json b/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json index 87700cfc..81073eab 100644 --- a/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json +++ b/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n bytes32 indexed relayHash,\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\r\n for (uint32 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint32).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 relayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayHash,\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n bytes32 indexed relayHash,\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\r\n for (uint32 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint32).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 relayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayHash,\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(wrappedNativeToken) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(wrappedNativeToken) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {}\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {}\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,25 +155,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json b/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json index 582dc2ea..c017c42f 100644 --- a/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json +++ b/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json @@ -2,52 +2,52 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./HubPoolInterface.sol\";\nimport \"./Lockable.sol\";\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\nimport \"@uma/core/contracts/common/implementation/AncillaryData.sol\";\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\n\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\n * disabled by the admin.\n */\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\n // can be submitted.\n RootBundle public rootBundleProposal;\n\n // Whether the bundle proposal process is paused.\n bool public paused;\n\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\n mapping(bytes32 => address) private poolRebalanceRoutes;\n\n // Mapping of L1 token addresses to the associated pool information.\n mapping(address => PooledToken) public pooledTokens;\n\n // Mapping of chainId to the associated adapter and spokePool contracts.\n mapping(uint256 => CrossChainContract) public crossChainContracts;\n\n // WETH contract for Ethereum.\n WETH9 public immutable weth;\n\n // Helper factory to deploy new LP tokens for enabled L1 tokens\n LpTokenFactoryInterface public immutable lpTokenFactory;\n\n // Finder contract for this network.\n FinderInterface public immutable finder;\n\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\n\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\n // the full amount of fees entitled to LPs in ~ 7.72 days, just over the standard L2 7 day liveness.\n uint256 public lpFeeRatePerSecond = 1500000000000;\n\n // Mapping of l1TokenAddress to cumulative unclaimed protocol tokens that can be sent to the protocolFeeCaptureAddress\n // at any time. This enables the protocol to reallocate some percentage of LP fees elsewhere.\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\n\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\n address public protocolFeeCaptureAddress;\n\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\n uint256 public protocolFeeCapturePct;\n\n // Token used to bond the data worker for proposing relayer refund bundles.\n IERC20 public bondToken;\n\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\n uint256 public bondAmount;\n\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\n uint32 public liveness = 7200;\n\n event Paused(bool indexed isPaused);\n\n event EmergencyRootBundleDeleted(\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\n\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\n\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\n\n event LivenessSet(uint256 newLiveness);\n\n event IdentifierSet(bytes32 newIdentifier);\n\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\n\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\n\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\n\n event LiquidityAdded(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensMinted,\n address indexed liquidityProvider\n );\n event LiquidityRemoved(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensBurnt,\n address indexed liquidityProvider\n );\n event SetPoolRebalanceRoute(\n uint256 indexed destinationChainId,\n address indexed l1Token,\n address indexed destinationToken\n );\n event SetEnableDepositRoute(\n uint256 indexed originChainId,\n uint256 indexed destinationChainId,\n address indexed originToken,\n bool depositsEnabled\n );\n event ProposeRootBundle(\n uint32 requestExpirationTimestamp,\n uint64 unclaimedPoolRebalanceLeafCount,\n uint256[] bundleEvaluationBlockNumbers,\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n event RootBundleExecuted(\n uint256 groupIndex,\n uint256 indexed leafId,\n uint256 indexed chainId,\n address[] l1Token,\n uint256[] bundleLpFees,\n int256[] netSendAmount,\n int256[] runningBalance,\n address indexed caller\n );\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\n\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\n\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\n\n modifier noActiveRequests() {\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\n _;\n }\n\n modifier unpaused() {\n require(!paused, \"Proposal process has been paused\");\n _;\n }\n\n modifier zeroOptimisticOracleApproval() {\n _;\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\n }\n\n /**\n * @notice Construct HubPool.\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\n * @param _finder Finder address.\n * @param _weth WETH address.\n * @param _timer Timer address.\n */\n constructor(\n LpTokenFactoryInterface _lpTokenFactory,\n FinderInterface _finder,\n WETH9 _weth,\n address _timer\n ) Testable(_timer) {\n lpTokenFactory = _lpTokenFactory;\n finder = _finder;\n weth = _weth;\n protocolFeeCaptureAddress = owner();\n }\n\n /*************************************************\n * ADMIN FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function setPaused(bool pause) public onlyOwner nonReentrant {\n paused = pause;\n emit Paused(pause);\n }\n\n /**\n * @notice This allows for the deletion of the active proposal in case of emergency.\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\n */\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n emit EmergencyRootBundleDeleted(\n rootBundleProposal.poolRebalanceRoot,\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot,\n rootBundleProposal.proposer\n );\n delete rootBundleProposal;\n }\n\n /**\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\n * contract only allows the owner to call this method directly or indirectly.\n * @param chainId Chain with SpokePool to send message to.\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\n */\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\n public\n override\n onlyOwner\n nonReentrant\n {\n _relaySpokePoolAdminFunction(chainId, functionData);\n }\n\n /**\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\n * @param newProtocolFeeCapturePct New protocol fee capture %.\n */\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\n public\n override\n onlyOwner\n nonReentrant\n {\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\n protocolFeeCapturePct = newProtocolFeeCapturePct;\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\n }\n\n /**\n * @notice Sets bond token and amount. Callable only by owner.\n * @param newBondToken New bond currency.\n * @param newBondAmount New bond amount.\n */\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\n public\n override\n onlyOwner\n noActiveRequests\n nonReentrant\n {\n // Bond should not be great than final fee otherwise every proposal will get cancelled in a dispute.\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\n require(newBondAmount != 0, \"bond equal to final fee\");\n\n // Check that this token is on the whitelist.\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\n );\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\n\n // The bond should be the passed in bondAmount + the final fee.\n bondToken = newBondToken;\n bondAmount = newBondAmount + _getBondTokenFinalFee();\n emit BondSet(address(newBondToken), bondAmount);\n }\n\n /**\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\n * @param newLiveness New liveness period.\n */\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\n require(newLiveness > 10 minutes, \"Liveness too short\");\n liveness = newLiveness;\n emit LivenessSet(newLiveness);\n }\n\n /**\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\n * @param newIdentifier New identifier.\n */\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\n );\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\n identifier = newIdentifier;\n emit IdentifierSet(newIdentifier);\n }\n\n /**\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\n * @param l2ChainId Chain to set contracts for.\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\n */\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) public override onlyOwner nonReentrant {\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\n }\n\n /**\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\n * containing this l1 token + destination chain ID combination.\n * @param destinationChainId Destination chain where destination token resides.\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\n * destination chain ID.\n * @param destinationToken Destination chain counterpart of L1 token.\n */\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) public override onlyOwner nonReentrant {\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\n }\n\n /**\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\n * SpokePool to another one. Callable only by owner.\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\n * to the destination chain to refund the relayer.\n * @param originChainId Chain where token deposit occurs.\n * @param destinationChainId Chain where token depositor wants to receive funds.\n * @param originToken Token sent in deposit.\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\n */\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) public override nonReentrant onlyOwner {\n _relaySpokePoolAdminFunction(\n originChainId,\n abi.encodeWithSignature(\n \"setEnableRoute(address,uint256,bool)\",\n originToken,\n destinationChainId,\n depositsEnabled\n )\n );\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\n }\n\n /**\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\n * Callable only by owner.\n * @param l1Token Token to provide liquidity for.\n */\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\n if (pooledTokens[l1Token].lpToken == address(0)) {\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n pooledTokens[l1Token].isEnabled = true;\n\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /**\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\n * @param l1Token Token to disable liquidity provision for.\n */\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n pooledTokens[l1Token].isEnabled = false;\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /*************************************************\n * LIQUIDITY PROVIDER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\n * increments from the time that they enter the pool to reflect their accrued fees.\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\n * @param l1Token Token to deposit into this contract.\n * @param l1TokenAmount Amount of liquidity to provide.\n */\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\n // Else, msg.value must be set to 0.\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\n\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\n // first before transferring any tokens to this contract to ensure synchronization.\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\n\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\n\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\n }\n\n /**\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\n * @param l1Token Token to redeem LP share for.\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\n * via public exchangeRateCurrent method.\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\n * if this value is set to False, then the calling contract should have a way to handle WETH.\n */\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) public override nonReentrant {\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\n\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\n\n if (sendEth) {\n weth.withdraw(l1TokensToReturn);\n payable(msg.sender).transfer(l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\n } else {\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\n }\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\n }\n\n /**\n * @notice Returns exchange rate of L1 token to LP token.\n * @param l1Token L1 token redeemable by burning LP token.\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\n */\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _exchangeRateCurrent(l1Token);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\n * @param l1Token L1 token to query utilization for.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\n */\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _liquidityUtilizationPostRelay(l1Token, 0);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\n * relayedAmount of tokens to be withdrawn from the pool.\n * @param l1Token L1 token to query utilization for.\n * @param relayedAmount The higher this amount, the higher the utilization.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\n */\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\n public\n nonReentrant\n returns (uint256)\n {\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\n }\n\n /**\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\n */\n function sync(address l1Token) public override nonReentrant {\n _sync(l1Token);\n }\n\n /*************************************************\n * DATA WORKER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\n * called; moreover, this method can't be called again until all leaves are executed.\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\n * refund relayers on their chosen refund chainId.\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\n * fulfill slow relays.\n */\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) public override nonReentrant noActiveRequests unpaused {\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\n\n uint32 requestExpirationTimestamp = uint32(getCurrentTime()) + liveness;\n\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time.\n\n rootBundleProposal.requestExpirationTimestamp = requestExpirationTimestamp;\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\n rootBundleProposal.proposer = msg.sender;\n\n // Pull bondAmount of bondToken from the caller.\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n\n emit ProposeRootBundle(\n requestExpirationTimestamp,\n poolRebalanceLeafCount,\n bundleEvaluationBlockNumbers,\n poolRebalanceRoot,\n relayerRefundRoot,\n slowRelayRoot,\n msg.sender\n );\n }\n\n /**\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\n * relay roots to the SpokePool on the network specified in the leaf.\n * @dev In some cases, will instruct spokePool to send funds back to L1.\n * @notice Deletes the published root bundle if this is the last leaf to be executed in the root bundle.\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\n * @param leafId Index of this executed leaf within the poolRebalance tree.\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\n */\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) public nonReentrant unpaused {\n require(getCurrentTime() > rootBundleProposal.requestExpirationTimestamp, \"Not passed liveness\");\n\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\n\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\n require(\n MerkleLib.verifyPoolRebalance(\n rootBundleProposal.poolRebalanceRoot,\n PoolRebalanceLeaf({\n chainId: chainId,\n groupIndex: groupIndex,\n bundleLpFees: bundleLpFees,\n netSendAmounts: netSendAmounts,\n runningBalances: runningBalances,\n leafId: leafId,\n l1Tokens: l1Tokens\n }),\n proof\n ),\n \"Bad Proof\"\n );\n\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\n // is set improperly.\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Set the leafId in the claimed bitmap.\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\n\n // Decrement the unclaimedPoolRebalanceLeafCount.\n rootBundleProposal.unclaimedPoolRebalanceLeafCount--;\n\n // Relay each L1 token to destination chain.\n\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\n // then this internal method will revert. In this case the admin will have to associate a destination token\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\n // determine if the relayers used the correct destination token for a given origin token.\n _sendTokensToChainAndUpdatePooledTokenTrackers(\n adapter,\n spokePool,\n chainId,\n l1Tokens,\n netSendAmounts,\n bundleLpFees\n );\n\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\n if (groupIndex == 0) {\n // Relay root bundles to spoke pool on destination chain by\n // performing delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n abi.encodeWithSignature(\n \"relayRootBundle(bytes32,bytes32)\",\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot\n ) // message\n )\n );\n require(success, \"delegatecall failed\");\n }\n\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n\n emit RootBundleExecuted(\n groupIndex,\n leafId,\n chainId,\n l1Tokens,\n bundleLpFees,\n netSendAmounts,\n runningBalances,\n msg.sender\n );\n }\n\n /**\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\n */\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\n uint32 currentTime = uint32(getCurrentTime());\n require(currentTime <= rootBundleProposal.requestExpirationTimestamp, \"Request passed liveness\");\n\n // Request price from OO and dispute it.\n uint256 finalFee = _getBondTokenFinalFee();\n\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\n // data in this ancillary data that is already included in the ProposeRootBundle event.\n\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\n if (finalFee >= bondAmount) {\n _cancelBundle();\n return;\n }\n\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\n\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n try\n optimisticOracle.requestAndProposePriceFor(\n identifier,\n currentTime,\n \"\",\n bondToken,\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\n // proposal has passed the challenge period.\n 0,\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\n bondAmount - finalFee,\n // Set the Optimistic oracle liveness for the price request.\n liveness,\n rootBundleProposal.proposer,\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\n int256(1e18)\n )\n returns (uint256) {\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\n // to transfer than intended.\n bondToken.safeApprove(address(optimisticOracle), 0);\n } catch {\n // Cancel the bundle since the proposal failed.\n _cancelBundle();\n return;\n }\n\n // Dispute the request that we just sent.\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\n proposer: rootBundleProposal.proposer,\n disputer: address(0),\n currency: bondToken,\n settled: false,\n proposedPrice: int256(1e18),\n resolvedPrice: 0,\n expirationTime: currentTime + liveness,\n reward: 0,\n finalFee: finalFee,\n bond: bondAmount - finalFee,\n customLiveness: liveness\n });\n\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\n delete rootBundleProposal;\n\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\n\n emit RootBundleDisputed(msg.sender, currentTime);\n }\n\n /**\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\n * @param l1Token Token whose protocol fees the caller wants to disburse.\n */\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\n }\n\n /**\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\n * @param destinationChainId Where destination token is deployed.\n * @param l1Token Ethereum version token.\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\n * the l1Token to the destination chain.\n */\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n override\n returns (address destinationToken)\n {\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\n }\n\n /**\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\n * Arbitrum calls, but may also be needed for others.\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\n */\n function loadEthForL2Calls() public payable override {}\n\n /*************************************************\n * INTERNAL FUNCTIONS *\n *************************************************/\n\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\n // with no loss of funds, thereby enabling a new bundle to be added.\n function _cancelBundle() internal {\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\n delete rootBundleProposal;\n emit RootBundleCanceled(msg.sender, getCurrentTime());\n }\n\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\n return\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\n }\n\n function _getBondTokenFinalFee() internal view returns (uint256) {\n return\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\n .computeFinalFee(address(bondToken))\n .rawValue;\n }\n\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\n address adapter,\n address spokePool,\n uint256 chainId,\n address[] memory l1Tokens,\n int256[] memory netSendAmounts,\n uint256[] memory bundleLpFees\n ) internal {\n for (uint32 i = 0; i < l1Tokens.length; i++) {\n address l1Token = l1Tokens[i];\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\n // could send tokens to the 0x0 address on the L2.\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\n require(l2Token != address(0), \"Route not whitelisted\");\n\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\n if (netSendAmounts[i] > 0) {\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\n // complexity in exchange for lower gas costs.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayTokens(address,address,uint256,address)\",\n l1Token, // l1Token.\n l2Token, // l2Token.\n uint256(netSendAmounts[i]), // amount.\n spokePool // to. This should be the spokePool.\n )\n );\n require(success, \"delegatecall failed\");\n\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\n }\n\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\n }\n }\n\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\n\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\n // gradually increase over time as undistributedLpFees goes to zero.\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\n // int will always be positive so there is no risk in underflow in type casting in the return line.\n int256 numerator = int256(pooledToken.liquidReserves) +\n pooledToken.utilizedReserves -\n int256(pooledToken.undistributedLpFees);\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\n }\n\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\n pooledToken.undistributedLpFees -= accumulatedFees;\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\n }\n\n function _sync(address l1Token) internal {\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\n // action from L2 -> L1 has concluded and the local accounting can be updated.\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\n // active request.\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\n // dropped onto the contract, exceeding the liquidReserves.\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\n }\n }\n\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\n PooledToken memory pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 flooredUtilizedReserves = pooledToken.utilizedReserves > 0 ? uint256(pooledToken.utilizedReserves) : 0;\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\n uint256 denominator = pooledToken.liquidReserves + flooredUtilizedReserves;\n\n // If the denominator equals zero, return 1e18 (max utilization).\n if (denominator == 0) return 1e18;\n\n // In all other cases, return the utilization ratio.\n return (numerator * 1e18) / denominator;\n }\n\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\n\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\n if (lpFeesCaptured > 0) {\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\n }\n\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\n }\n\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Perform delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n functionData\n )\n );\n require(success, \"delegatecall failed\");\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\n }\n\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\n return keccak256(abi.encode(l1Token, destinationChainId));\n }\n\n function _getInitializedCrossChainContracts(uint256 chainId)\n internal\n view\n returns (address adapter, address spokePool)\n {\n adapter = crossChainContracts[chainId].adapter;\n spokePool = crossChainContracts[chainId].spokePool;\n require(spokePool != address(0), \"SpokePool not initialized\");\n require(adapter.isContract(), \"Adapter not initialized\");\n }\n\n function _activeRequest() internal view returns (bool) {\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\n }\n\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\n function _depositEthToWeth() internal {\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\n }\n\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\n fallback() external payable {\n _depositEthToWeth();\n }\n\n receive() external payable {\n _depositEthToWeth();\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./HubPoolInterface.sol\";\nimport \"./Lockable.sol\";\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\nimport \"@uma/core/contracts/common/implementation/AncillaryData.sol\";\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\n\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\n * disabled by the admin.\n */\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\n // can be submitted.\n RootBundle public rootBundleProposal;\n\n // Whether the bundle proposal process is paused.\n bool public paused;\n\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\n mapping(bytes32 => address) private poolRebalanceRoutes;\n\n // Mapping of L1 token addresses to the associated pool information.\n mapping(address => PooledToken) public pooledTokens;\n\n // Mapping of chainId to the associated adapter and spokePool contracts.\n mapping(uint256 => CrossChainContract) public crossChainContracts;\n\n // WETH contract for Ethereum.\n WETH9 public immutable weth;\n\n // Helper factory to deploy new LP tokens for enabled L1 tokens\n LpTokenFactoryInterface public immutable lpTokenFactory;\n\n // Finder contract for this network.\n FinderInterface public immutable finder;\n\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\n\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\n // the full amount of fees entitled to LPs in ~ 7.72 days, just over the standard L2 7 day liveness.\n uint256 public lpFeeRatePerSecond = 1500000000000;\n\n // Mapping of l1TokenAddress to cumulative unclaimed protocol tokens that can be sent to the protocolFeeCaptureAddress\n // at any time. This enables the protocol to reallocate some percentage of LP fees elsewhere.\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\n\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\n address public protocolFeeCaptureAddress;\n\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\n uint256 public protocolFeeCapturePct;\n\n // Token used to bond the data worker for proposing relayer refund bundles.\n IERC20 public bondToken;\n\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\n uint256 public bondAmount;\n\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\n uint32 public liveness = 7200;\n\n event Paused(bool indexed isPaused);\n\n event EmergencyRootBundleDeleted(\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\n\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\n\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\n\n event LivenessSet(uint256 newLiveness);\n\n event IdentifierSet(bytes32 newIdentifier);\n\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\n\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\n\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\n\n event LiquidityAdded(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensMinted,\n address indexed liquidityProvider\n );\n event LiquidityRemoved(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensBurnt,\n address indexed liquidityProvider\n );\n event SetPoolRebalanceRoute(\n uint256 indexed destinationChainId,\n address indexed l1Token,\n address indexed destinationToken\n );\n event SetEnableDepositRoute(\n uint256 indexed originChainId,\n uint256 indexed destinationChainId,\n address indexed originToken,\n bool depositsEnabled\n );\n event ProposeRootBundle(\n uint32 requestExpirationTimestamp,\n uint64 unclaimedPoolRebalanceLeafCount,\n uint256[] bundleEvaluationBlockNumbers,\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n event RootBundleExecuted(\n uint256 groupIndex,\n uint256 indexed leafId,\n uint256 indexed chainId,\n address[] l1Token,\n uint256[] bundleLpFees,\n int256[] netSendAmount,\n int256[] runningBalance,\n address indexed caller\n );\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\n\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\n\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\n\n modifier noActiveRequests() {\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\n _;\n }\n\n modifier unpaused() {\n require(!paused, \"Proposal process has been paused\");\n _;\n }\n\n modifier zeroOptimisticOracleApproval() {\n _;\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\n }\n\n /**\n * @notice Construct HubPool.\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\n * @param _finder Finder address.\n * @param _weth WETH address.\n * @param _timer Timer address.\n */\n constructor(\n LpTokenFactoryInterface _lpTokenFactory,\n FinderInterface _finder,\n WETH9 _weth,\n address _timer\n ) Testable(_timer) {\n lpTokenFactory = _lpTokenFactory;\n finder = _finder;\n weth = _weth;\n protocolFeeCaptureAddress = owner();\n }\n\n /*************************************************\n * ADMIN FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function setPaused(bool pause) public onlyOwner nonReentrant {\n paused = pause;\n emit Paused(pause);\n }\n\n /**\n * @notice This allows for the deletion of the active proposal in case of emergency.\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\n */\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n emit EmergencyRootBundleDeleted(\n rootBundleProposal.poolRebalanceRoot,\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot,\n rootBundleProposal.proposer\n );\n delete rootBundleProposal;\n }\n\n /**\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\n * contract only allows the owner to call this method directly or indirectly.\n * @param chainId Chain with SpokePool to send message to.\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\n */\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\n public\n override\n onlyOwner\n nonReentrant\n {\n _relaySpokePoolAdminFunction(chainId, functionData);\n }\n\n /**\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\n * @param newProtocolFeeCapturePct New protocol fee capture %.\n */\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\n public\n override\n onlyOwner\n nonReentrant\n {\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\n protocolFeeCapturePct = newProtocolFeeCapturePct;\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\n }\n\n /**\n * @notice Sets bond token and amount. Callable only by owner.\n * @param newBondToken New bond currency.\n * @param newBondAmount New bond amount.\n */\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\n public\n override\n onlyOwner\n noActiveRequests\n nonReentrant\n {\n // Bond should not be great than final fee otherwise every proposal will get cancelled in a dispute.\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\n require(newBondAmount != 0, \"bond equal to final fee\");\n\n // Check that this token is on the whitelist.\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\n );\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\n\n // The bond should be the passed in bondAmount + the final fee.\n bondToken = newBondToken;\n bondAmount = newBondAmount + _getBondTokenFinalFee();\n emit BondSet(address(newBondToken), bondAmount);\n }\n\n /**\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\n * @param newLiveness New liveness period.\n */\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\n require(newLiveness > 10 minutes, \"Liveness too short\");\n liveness = newLiveness;\n emit LivenessSet(newLiveness);\n }\n\n /**\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\n * @param newIdentifier New identifier.\n */\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\n );\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\n identifier = newIdentifier;\n emit IdentifierSet(newIdentifier);\n }\n\n /**\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\n * @param l2ChainId Chain to set contracts for.\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\n */\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) public override onlyOwner nonReentrant {\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\n }\n\n /**\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\n * containing this l1 token + destination chain ID combination.\n * @param destinationChainId Destination chain where destination token resides.\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\n * destination chain ID.\n * @param destinationToken Destination chain counterpart of L1 token.\n */\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) public override onlyOwner nonReentrant {\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\n }\n\n /**\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\n * SpokePool to another one. Callable only by owner.\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\n * to the destination chain to refund the relayer.\n * @param originChainId Chain where token deposit occurs.\n * @param destinationChainId Chain where token depositor wants to receive funds.\n * @param originToken Token sent in deposit.\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\n */\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) public override nonReentrant onlyOwner {\n _relaySpokePoolAdminFunction(\n originChainId,\n abi.encodeWithSignature(\n \"setEnableRoute(address,uint256,bool)\",\n originToken,\n destinationChainId,\n depositsEnabled\n )\n );\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\n }\n\n /**\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\n * Callable only by owner.\n * @param l1Token Token to provide liquidity for.\n */\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\n if (pooledTokens[l1Token].lpToken == address(0)) {\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n pooledTokens[l1Token].isEnabled = true;\n\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /**\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\n * @param l1Token Token to disable liquidity provision for.\n */\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n pooledTokens[l1Token].isEnabled = false;\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /*************************************************\n * LIQUIDITY PROVIDER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\n * increments from the time that they enter the pool to reflect their accrued fees.\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\n * @param l1Token Token to deposit into this contract.\n * @param l1TokenAmount Amount of liquidity to provide.\n */\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\n // Else, msg.value must be set to 0.\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\n\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\n // first before transferring any tokens to this contract to ensure synchronization.\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\n\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\n\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\n }\n\n /**\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\n * @param l1Token Token to redeem LP share for.\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\n * via public exchangeRateCurrent method.\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\n * if this value is set to False, then the calling contract should have a way to handle WETH.\n */\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) public override nonReentrant {\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\n\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\n\n if (sendEth) {\n weth.withdraw(l1TokensToReturn);\n payable(msg.sender).transfer(l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\n } else {\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\n }\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\n }\n\n /**\n * @notice Returns exchange rate of L1 token to LP token.\n * @param l1Token L1 token redeemable by burning LP token.\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\n */\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _exchangeRateCurrent(l1Token);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\n * @param l1Token L1 token to query utilization for.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\n */\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _liquidityUtilizationPostRelay(l1Token, 0);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\n * relayedAmount of tokens to be withdrawn from the pool.\n * @param l1Token L1 token to query utilization for.\n * @param relayedAmount The higher this amount, the higher the utilization.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\n */\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\n public\n nonReentrant\n returns (uint256)\n {\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\n }\n\n /**\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\n */\n function sync(address l1Token) public override nonReentrant {\n _sync(l1Token);\n }\n\n /*************************************************\n * DATA WORKER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\n * called; moreover, this method can't be called again until all leaves are executed.\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\n * refund relayers on their chosen refund chainId.\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\n * fulfill slow relays.\n */\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) public override nonReentrant noActiveRequests unpaused {\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\n\n uint32 requestExpirationTimestamp = uint32(getCurrentTime()) + liveness;\n\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time.\n\n rootBundleProposal.requestExpirationTimestamp = requestExpirationTimestamp;\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\n rootBundleProposal.proposer = msg.sender;\n\n // Pull bondAmount of bondToken from the caller.\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n\n emit ProposeRootBundle(\n requestExpirationTimestamp,\n poolRebalanceLeafCount,\n bundleEvaluationBlockNumbers,\n poolRebalanceRoot,\n relayerRefundRoot,\n slowRelayRoot,\n msg.sender\n );\n }\n\n /**\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\n * relay roots to the SpokePool on the network specified in the leaf.\n * @dev In some cases, will instruct spokePool to send funds back to L1.\n * @notice Deletes the published root bundle if this is the last leaf to be executed in the root bundle.\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\n * @param leafId Index of this executed leaf within the poolRebalance tree.\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\n */\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) public nonReentrant unpaused {\n require(getCurrentTime() > rootBundleProposal.requestExpirationTimestamp, \"Not passed liveness\");\n\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\n\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\n require(\n MerkleLib.verifyPoolRebalance(\n rootBundleProposal.poolRebalanceRoot,\n PoolRebalanceLeaf({\n chainId: chainId,\n groupIndex: groupIndex,\n bundleLpFees: bundleLpFees,\n netSendAmounts: netSendAmounts,\n runningBalances: runningBalances,\n leafId: leafId,\n l1Tokens: l1Tokens\n }),\n proof\n ),\n \"Bad Proof\"\n );\n\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\n // is set improperly.\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Set the leafId in the claimed bitmap.\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\n\n // Decrement the unclaimedPoolRebalanceLeafCount.\n rootBundleProposal.unclaimedPoolRebalanceLeafCount--;\n\n // Relay each L1 token to destination chain.\n\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\n // then this internal method will revert. In this case the admin will have to associate a destination token\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\n // determine if the relayers used the correct destination token for a given origin token.\n _sendTokensToChainAndUpdatePooledTokenTrackers(\n adapter,\n spokePool,\n chainId,\n l1Tokens,\n netSendAmounts,\n bundleLpFees\n );\n\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\n if (groupIndex == 0) {\n // Relay root bundles to spoke pool on destination chain by\n // performing delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n abi.encodeWithSignature(\n \"relayRootBundle(bytes32,bytes32)\",\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot\n ) // message\n )\n );\n require(success, \"delegatecall failed\");\n }\n\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n\n emit RootBundleExecuted(\n groupIndex,\n leafId,\n chainId,\n l1Tokens,\n bundleLpFees,\n netSendAmounts,\n runningBalances,\n msg.sender\n );\n }\n\n /**\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\n */\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\n uint32 currentTime = uint32(getCurrentTime());\n require(currentTime <= rootBundleProposal.requestExpirationTimestamp, \"Request passed liveness\");\n\n // Request price from OO and dispute it.\n uint256 finalFee = _getBondTokenFinalFee();\n\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\n // data in this ancillary data that is already included in the ProposeRootBundle event.\n\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\n if (finalFee >= bondAmount) {\n _cancelBundle();\n return;\n }\n\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\n\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n try\n optimisticOracle.requestAndProposePriceFor(\n identifier,\n currentTime,\n \"\",\n bondToken,\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\n // proposal has passed the challenge period.\n 0,\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\n bondAmount - finalFee,\n // Set the Optimistic oracle liveness for the price request.\n liveness,\n rootBundleProposal.proposer,\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\n int256(1e18)\n )\n returns (uint256) {\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\n // to transfer than intended.\n bondToken.safeApprove(address(optimisticOracle), 0);\n } catch {\n // Cancel the bundle since the proposal failed.\n _cancelBundle();\n return;\n }\n\n // Dispute the request that we just sent.\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\n proposer: rootBundleProposal.proposer,\n disputer: address(0),\n currency: bondToken,\n settled: false,\n proposedPrice: int256(1e18),\n resolvedPrice: 0,\n expirationTime: currentTime + liveness,\n reward: 0,\n finalFee: finalFee,\n bond: bondAmount - finalFee,\n customLiveness: liveness\n });\n\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\n delete rootBundleProposal;\n\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\n\n emit RootBundleDisputed(msg.sender, currentTime);\n }\n\n /**\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\n * @param l1Token Token whose protocol fees the caller wants to disburse.\n */\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\n }\n\n /**\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\n * @param destinationChainId Where destination token is deployed.\n * @param l1Token Ethereum version token.\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\n * the l1Token to the destination chain.\n */\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n override\n returns (address destinationToken)\n {\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\n }\n\n /**\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\n * Arbitrum calls, but may also be needed for others.\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\n */\n function loadEthForL2Calls() public payable override {}\n\n /*************************************************\n * INTERNAL FUNCTIONS *\n *************************************************/\n\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\n // with no loss of funds, thereby enabling a new bundle to be added.\n function _cancelBundle() internal {\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\n delete rootBundleProposal;\n emit RootBundleCanceled(msg.sender, getCurrentTime());\n }\n\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\n return\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\n }\n\n function _getBondTokenFinalFee() internal view returns (uint256) {\n return\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\n .computeFinalFee(address(bondToken))\n .rawValue;\n }\n\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\n address adapter,\n address spokePool,\n uint256 chainId,\n address[] memory l1Tokens,\n int256[] memory netSendAmounts,\n uint256[] memory bundleLpFees\n ) internal {\n for (uint32 i = 0; i < l1Tokens.length; i++) {\n address l1Token = l1Tokens[i];\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\n // could send tokens to the 0x0 address on the L2.\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\n require(l2Token != address(0), \"Route not whitelisted\");\n\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\n if (netSendAmounts[i] > 0) {\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\n // complexity in exchange for lower gas costs.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayTokens(address,address,uint256,address)\",\n l1Token, // l1Token.\n l2Token, // l2Token.\n uint256(netSendAmounts[i]), // amount.\n spokePool // to. This should be the spokePool.\n )\n );\n require(success, \"delegatecall failed\");\n\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\n }\n\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\n }\n }\n\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\n\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\n // gradually increase over time as undistributedLpFees goes to zero.\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\n // int will always be positive so there is no risk in underflow in type casting in the return line.\n int256 numerator = int256(pooledToken.liquidReserves) +\n pooledToken.utilizedReserves -\n int256(pooledToken.undistributedLpFees);\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\n }\n\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\n pooledToken.undistributedLpFees -= accumulatedFees;\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\n }\n\n function _sync(address l1Token) internal {\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\n // action from L2 -> L1 has concluded and the local accounting can be updated.\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\n // active request.\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\n // dropped onto the contract, exceeding the liquidReserves.\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\n }\n }\n\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\n PooledToken memory pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 flooredUtilizedReserves = pooledToken.utilizedReserves > 0 ? uint256(pooledToken.utilizedReserves) : 0;\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\n uint256 denominator = pooledToken.liquidReserves + flooredUtilizedReserves;\n\n // If the denominator equals zero, return 1e18 (max utilization).\n if (denominator == 0) return 1e18;\n\n // In all other cases, return the utilization ratio.\n return (numerator * 1e18) / denominator;\n }\n\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\n\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\n if (lpFeesCaptured > 0) {\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\n }\n\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\n }\n\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Perform delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n functionData\n )\n );\n require(success, \"delegatecall failed\");\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\n }\n\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\n return keccak256(abi.encode(l1Token, destinationChainId));\n }\n\n function _getInitializedCrossChainContracts(uint256 chainId)\n internal\n view\n returns (address adapter, address spokePool)\n {\n adapter = crossChainContracts[chainId].adapter;\n spokePool = crossChainContracts[chainId].spokePool;\n require(spokePool != address(0), \"SpokePool not initialized\");\n require(adapter.isContract(), \"Adapter not initialized\");\n }\n\n function _activeRequest() internal view returns (bool) {\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\n }\n\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\n function _depositEthToWeth() internal {\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\n }\n\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\n fallback() external payable {\n _depositEthToWeth();\n }\n\n receive() external payable {\n _depositEthToWeth();\n }\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -62,19 +62,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -83,7 +83,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json b/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json index f246a5bb..a44976bf 100644 --- a/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json +++ b/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 chainId_;\n\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {}\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {}\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"OVM_XCHAIN: messenger contract unauthenticated\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,34 +113,34 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -149,25 +149,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json b/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json index ce0d44f4..86f3f81e 100644 --- a/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json +++ b/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -26,76 +26,76 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -110,13 +110,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -125,58 +125,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -185,22 +185,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { From cd340485989f848d6bbd5ea93200d2b577c5b1ad Mon Sep 17 00:00:00 2001 From: Matt Rice Date: Fri, 7 Jul 2023 17:35:24 -0400 Subject: [PATCH 2/2] WIP Signed-off-by: Matt Rice --- .../arbitrum-goerli/Arbitrum_SpokePool.json | 2 +- .../2703c51b0457010edb5371429c04306b.json | 80 ++++++------- .../arbitrum-rinkeby/Arbitrum_SpokePool.json | 2 +- .../c8b9349311d8b5049b613ac98eb998d0.json | 70 ++++++------ deployments/arbitrum/Arbitrum_SpokePool.json | 2 +- .../1a5892b796c4f5bdf21d8cd0d15027f4.json | 78 ++++++------- deployments/boba/Boba_SpokePool.json | 2 +- .../4d00864cb95f68f23bc763892eeb3451.json | 78 ++++++------- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 ++++++------- deployments/goerli/AcrossConfigStore.json | 2 +- .../goerli/AcrossMerkleDistributor.json | 2 +- deployments/goerli/Arbitrum_Adapter.json | 2 +- deployments/goerli/Ethereum_Adapter.json | 2 +- deployments/goerli/Ethereum_SpokePool.json | 2 +- deployments/goerli/LpTokenFactory.json | 2 +- deployments/goerli/ZkSync_Adapter.json | 2 +- .../0c0f7cf4c33344752a752d4aad8f0613.json | 94 +++++++-------- .../4972f5cae7c6e9deea3ed342ae0a0eeb.json | 88 +++++++------- .../b9d6747074e2e4e0305d51ac3373cf9e.json | 94 +++++++-------- .../e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json | 108 +++++++++--------- .../f5a0c3a42678b8be065d2d7cfda0e784.json | 90 +++++++-------- deployments/kovan/AcrossConfigStore.json | 2 +- deployments/kovan/Ethereum_Adapter.json | 2 +- deployments/kovan/Ethereum_SpokePool.json | 2 +- deployments/kovan/LpTokenFactory.json | 2 +- deployments/kovan/Optimism_Adapter.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 ++++++------ .../f654478e897007c7ba14581b070ec005.json | 38 +++--- deployments/mainnet/AcrossConfigStore.json | 2 +- deployments/mainnet/Arbitrum_Adapter.json | 2 +- .../mainnet/Arbitrum_RescueAdapter.json | 2 +- .../mainnet/Arbitrum_SendTokensAdapter.json | 2 +- deployments/mainnet/Boba_Adapter.json | 2 +- deployments/mainnet/Ethereum_Adapter.json | 2 +- deployments/mainnet/Ethereum_SpokePool.json | 2 +- deployments/mainnet/LpTokenFactory.json | 2 +- deployments/mainnet/Optimism_Adapter.json | 2 +- deployments/mainnet/PolygonTokenBridger.json | 2 +- deployments/mainnet/Polygon_Adapter.json | 2 +- .../2433465a1be70a13b6719df6fea2831a.json | 72 ++++++------ .../375f3de1549a735f4b746d114c8a6633.json | 38 +++--- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 ++++++------- .../778ed9956c3f76e793496228f16e1373.json | 22 ++-- .../80d9895099d6448454133a653020a62d.json | 74 ++++++------ .../9ecc79ca0809d14763bad8554b06546b.json | 94 +++++++-------- .../a254ea7a050d78a978809e4c33fcb9ff.json | 6 +- .../aa94850b4a0bee17111a41299cfa0033.json | 94 +++++++-------- .../ac469a0c874627ad85d8b93b55e7f3fc.json | 76 ++++++------ .../b20d5afcf396996ae08652b8281973a7.json | 72 ++++++------ .../c2d6025a634518ca1feda7b98c45d21d.json | 76 ++++++------ .../f654478e897007c7ba14581b070ec005.json | 38 +++--- .../optimism-kovan/Optimism_SpokePool.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 ++++++------ deployments/optimism/Optimism_SpokePool.json | 2 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 ++++++------- .../polygon-mumbai/MintableERC1155.json | 2 +- .../polygon-mumbai/PolygonTokenBridger.json | 2 +- .../polygon-mumbai/Polygon_SpokePool.json | 2 +- .../200193942e0f09d7ebb5ccce1bc305e7.json | 2 +- .../2a98e0c4f048f0fda1d4cc9162127646.json | 2 +- .../c0d608dcade73b41bfb146ca48293092.json | 2 +- .../c2d6025a634518ca1feda7b98c45d21d.json | 76 ++++++------ deployments/polygon/MintableERC1155.json | 2 +- deployments/polygon/PolygonTokenBridger.json | 2 +- deployments/polygon/Polygon_SpokePool.json | 2 +- .../55c0117eb9fb2209b6f60673be44d9d8.json | 78 ++++++------- .../b20d5afcf396996ae08652b8281973a7.json | 72 ++++++------ .../ea9229ed188f1300c4a413d030dbf1b6.json | 2 +- deployments/rinkeby/Arbitrum_Adapter.json | 2 +- deployments/rinkeby/Ethereum_Adapter.json | 2 +- deployments/rinkeby/Ethereum_SpokePool.json | 2 +- deployments/rinkeby/LpTokenFactory.json | 2 +- deployments/rinkeby/Optimism_Adapter.json | 2 +- deployments/rinkeby/PolygonTokenBridger.json | 2 +- deployments/rinkeby/Polygon_Adapter.json | 2 +- deployments/rinkeby/RateModelStore.json | 2 +- .../1bf8793c065ccb196e5a60f53c731ca8.json | 74 ++++++------ .../2fe6c4b637a440a1380be3adbf7d9e12.json | 40 +++---- .../fc82eeb0fff4196cd4e0dfec8a3b3aca.json | 70 ++++++------ .../ee6ad487568ec11f1abbf35d827b46d3.json | 88 +++++++------- 80 files changed, 1229 insertions(+), 1229 deletions(-) diff --git a/deployments/arbitrum-goerli/Arbitrum_SpokePool.json b/deployments/arbitrum-goerli/Arbitrum_SpokePool.json index 3b51974c..3f196dfa 100644 --- a/deployments/arbitrum-goerli/Arbitrum_SpokePool.json +++ b/deployments/arbitrum-goerli/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "2703c51b0457010edb5371429c04306b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200482a3803806200482a8339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b60805161452162000309600039600081816101e401528181610dd001528181610e990152818161237e01528181612d2c0152612d8201526145216000f3fe6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json b/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json index 53154379..08b2be5e 100644 --- a/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json +++ b/deployments/arbitrum-goerli/solcInputs/2703c51b0457010edb5371429c04306b.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,46 +119,46 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -167,22 +167,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json b/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json index dca93736..695cae39 100644 --- a/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json +++ b/deployments/arbitrum-rinkeby/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundRoot().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayRoot().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit ETH if the originToken is WETH and this function will handle wrapping ETH.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // This array is grouped with the two above, and it represents the amount to send or request back from the\\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\\n // bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 requestExpirationTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0x71b427ffd4a1e8c0cc681bafe050c536d79464f12559e90172681e6745f2e7bc\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\\n // instruct this contract to wrap ETH when depositing.\\n WETH9 public immutable weth;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n bytes32 indexed relayHash,\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n weth = WETH9(_wethAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundRoot().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayRoot().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\\n * function will handle wrapping ETH.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\\n if (originToken == address(weth) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n weth.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n numberOfDeposits += 1;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayRoot(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(crossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(hubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(weth)).safeTransfer(to, amount);\\n } else {\\n weth.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is weth then unwrap and send eth.\\n if (relayData.destinationToken == address(weth)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 relayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayHash,\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x460bea0562b87af55699b2ec0e53735b2224039573f9c5243815541263588bc1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe0ae593c1cd9c8204f0b7a3f226a5d4bd30d580692d2ecb2a33548b5b4e75f12\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundRoot().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayRoot().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit ETH if the originToken is WETH and this function will handle wrapping ETH.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundRoot(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayRoot(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // This array is grouped with the two above, and it represents the amount to send or request back from the\\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\\n // bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 requestExpirationTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0x71b427ffd4a1e8c0cc681bafe050c536d79464f12559e90172681e6745f2e7bc\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\\n // instruct this contract to wrap ETH when depositing.\\n WETH9 public immutable weth;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n bytes32 indexed relayHash,\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n weth = WETH9(_wethAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundRoot().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayRoot().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\\n * function will handle wrapping ETH.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\\n if (originToken == address(weth) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n weth.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n numberOfDeposits += 1;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayRoot(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(crossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(hubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(weth)).safeTransfer(to, amount);\\n } else {\\n weth.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is weth then unwrap and send eth.\\n if (relayData.destinationToken == address(weth)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 relayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayHash,\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x460bea0562b87af55699b2ec0e53735b2224039573f9c5243815541263588bc1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayRoot(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundRoot(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe0ae593c1cd9c8204f0b7a3f226a5d4bd30d580692d2ecb2a33548b5b4e75f12\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004831380380620048318339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b608051614528620003096000396000818161030001528181610d4c01528181610e1501528181611fcf01528181612a5f0152612ab501526145286000f3fe6080604052600436106101c65760003560e01c806389a153cc116100f7578063daf9c21011610095578063ee2a53f811610064578063ee2a53f8146105e0578063f06850f614610615578063f500697c14610642578063ffc351a31461066257600080fd5b8063daf9c21014610530578063de7eba7814610573578063e190440214610593578063e282d5b9146105c057600080fd5b8063a1244c67116100d1578063a1244c671461048a578063ac9650d8146104c3578063c8356859146104e3578063c894c0ca1461051057600080fd5b806389a153cc146104375780638a7860ce146104575780639a8a05921461047757600080fd5b80633fc8cef3116101645780634e3485c81161013e5780634e3485c8146103555780635249fef1146103755780635285e058146103c057806357f6dcb8146103ed57600080fd5b80633fc8cef3146102ee5780634922897814610322578063493a4f841461033557600080fd5b8063272751c7116101a0578063272751c71461026b5780632752042e1461028b57806329cb924d146102ab578063364f01a6146102ce57600080fd5b80631c39c38d146101d25780631dfb2d021461022957806322f8e5661461024b57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506000546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023557600080fd5b50610249610244366004613629565b610682565b005b34801561025757600080fd5b50610249610266366004613644565b61070f565b34801561027757600080fd5b5061024961028636600461366b565b6107b8565b34801561029757600080fd5b506102496102a63660046136bf565b6108cf565b3480156102b757600080fd5b506102c06109d0565b604051908152602001610220565b3480156102da57600080fd5b506102496102e93660046136da565b610a88565b3480156102fa57600080fd5b506101ff7f000000000000000000000000000000000000000000000000000000000000000081565b610249610330366004613725565b610b17565b34801561034157600080fd5b5061024961035036600461378b565b610f7e565b34801561036157600080fd5b50610249610370366004613629565b6110a1565b34801561038157600080fd5b506103b06103903660046137ad565b600360209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610220565b3480156103cc57600080fd5b506001546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506002546104229074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610220565b34801561044357600080fd5b506102496104523660046137d7565b6110e7565b34801561046357600080fd5b50610249610472366004613644565b611243565b34801561048357600080fd5b50466102c0565b34801561049657600080fd5b50600254610422907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104d66104d1366004613875565b611317565b6040516102209190613960565b3480156104ef57600080fd5b506006546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561051c57600080fd5b5061024961052b366004613b78565b6114f1565b34801561053c57600080fd5b506101ff61054b366004613629565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b5061024961058e366004613629565b611575565b34801561059f57600080fd5b506002546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105cc57600080fd5b506102496105db366004613d0b565b6115bb565b3480156105ec57600080fd5b506106006105fb366004613644565b611719565b60408051928352602083019190915201610220565b34801561062157600080fd5b506102c0610630366004613644565b60056020526000908152604090205481565b34801561064e57600080fd5b5061024961065d366004613d7a565b611747565b34801561066e57600080fd5b5061024961067d366004613e41565b6117d3565b61068a61193e565b610692611a0a565b6106bf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611a8e565b61070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661073157600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561079d57600080fd5b505af11580156107b1573d6000803e3d6000fd5b5050505050565b6107c061193e565b6107c8611a0a565b6107f5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260036020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108d761193e565b6108df611a0a565b61090c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610a835760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7e9190613f1f565b905090565b504290565b610a9061193e565b610a98611a0a565b610ac5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610acf8282611b7a565b610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610b1f611a0a565b610b4c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832086845290915290205460ff16610beb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b600254610c919074010000000000000000000000000000000000000000900463ffffffff1682613f67565b63ffffffff16610c9f6109d0565b10158015610ce45750600254610cd39074010000000000000000000000000000000000000000900463ffffffff1682613f8c565b63ffffffff16610ce16109d0565b11155b610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610da55750600034115b15610e9957833414610e13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b5050505050610ebb565b610ebb73ffffffffffffffffffffffffffffffffffffffff8616333087611bf6565b610ef28446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611cd2565b6001600260188282829054906101000a900463ffffffff16610f149190613f8c565b92506101000a81548163ffffffff021916908363ffffffff160217905550610f76600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f8661193e565b610f8e611a0a565b610fbb600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60048054600181018255600091909152600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018490557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01828155604080518581526020810185905263ffffffff8416917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af910160405180910390a25050610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6110a961193e565b6110b1611a0a565b6110de600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611d63565b6110ef611a0a565b61111c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111914690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111cd82611dd2565b905060006111df82848b886000611e02565b90506111f082828a888760006120af565b505050611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61124b61193e565b611253611a0a565b611280600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6004818154811061129357611293613fb4565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610be2565b8167ffffffffffffffff81111561139a5761139a6139e0565b6040519080825280602002602001820160405280156113cd57816020015b60608152602001906001900390816113b85790505b50905060005b828110156114ea57600080308686858181106113f1576113f1613fb4565b90506020028101906114039190613fe3565b604051611411929190614048565b600060405180830381855af49150503d806000811461144c576040519150601f19603f3d011682016040523d82523d6000602084013e611451565b606091505b5091509150816114b75760448151101561146a57600080fd5b600481019050808060200190518101906114849190614088565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b808484815181106114ca576114ca613fb4565b6020026020010181905250505080806114e2906140e4565b9150506113d3565b5092915050565b6114f9611a0a565b611526600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115318383836121e4565b6108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61157d61193e565b611585611a0a565b6115b2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c8816125aa565b6115c3611a0a565b6115f0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b6116788446858585612696565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116c792919061411c565b60405180910390a3611713600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6004818154811061172957600080fd5b60009182526020909120600390910201805460019091015490915082565b61174f611a0a565b61177c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61178f8a8a8a8a8a468b8b8b8b8b612733565b611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6117db611a0a565b611808600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118158c87858585612696565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188a4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c682611dd2565b905060006118d882848d896000611e02565b90506118e982828c898760006120af565b505050611930600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b6001546119749073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610be2565b565b60005474010000000000000000000000000000000000000000900460ff16611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be2565b73ffffffffffffffffffffffffffffffffffffffff8116611b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610be2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117139085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526128b2565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001611de5919061413f565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff16108015611e3a57506706f05b59d3b200008560c0015167ffffffffffffffff16105b611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610be2565b606085015160008781526005602052604090205410611f1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610be2565b83600003611f2b575060006120a6565b611f4484848760c00151611f3f91906141e6565b6129be565b60008781526005602052604081205460608801519293508692611f679190614209565b905082811015611f9057809250611f8d83868960c00151611f8891906141e6565b6129ff565b91505b60008881526005602052604081208054859290611fae908490614220565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361203657836120235760408701516120239073ffffffffffffffffffffffffffffffffffffffff16333085611bf6565b612031876020015183612a28565b6120a3565b8361207057612031338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611bf6909392919063ffffffff16565b6120a3876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f6040516121d49c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b46826020015114612251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610be2565b8160400151518260a0015151146122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610be2565b600060048463ffffffff16815481106122df576122df613fb4565b906000526020600020906003020190506122fe81600101548484612bbf565b612364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610be2565b61237b81600201846060015163ffffffff16612bfa565b156123e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610be2565b6123f981600201846060015163ffffffff16612c3b565b60005b8360400151518163ffffffff1610156124a557600084604001518263ffffffff168151811061242d5761242d613fb4565b602002602001015190506000811115612492576124928560a001518363ffffffff168151811061245f5761245f613fb4565b602002602001015182876080015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b508061249d81614238565b9150506123fc565b5082511561253e576124b683612c79565b826080015173ffffffffffffffffffffffffffffffffffffffff16836060015163ffffffff1684602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f7186600001513360405161253592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b826060015163ffffffff168463ffffffff1684602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8660000151876040015188608001518960a001513360405161259c9594939291906142dc565b60405180910390a450505050565b73ffffffffffffffffffffffffffffffffffffffff8116612627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610be2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061271d82612e45565b905061272a878285612e80565b50505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061280860048463ffffffff16815481106127ef576127ef613fb4565b9060005260206000209060030201600001548284612f1e565b61286e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610be2565b600061287982611dd2565b905060006128908284856060015160006001611e02565b90506128a282826000808760016120af565b5050505050505050505050505050565b6000612914826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f369092919063ffffffff16565b8051909150156108ca5780806020019051810190612932919061433a565b6108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610be2565b60006129d282670de0b6b3a7640000614357565b67ffffffffffffffff166129ee84670de0b6b3a7640000614378565b6129f891906143e4565b9392505050565b6000670de0b6b3a7640000612a148382614357565b6129ee9067ffffffffffffffff1685614378565b73ffffffffffffffffffffffffffffffffffffffff82163b15612a8657610b1373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612b69565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b0e57600080fd5b505af1158015612b22573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ca573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ca9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c50565b6000612bf2828585604051602001612bd791906143f8565b60405160208183030381529060405280519060200120612f45565b949350505050565b600080612c09610100846143e4565b90506000612c1961010085614493565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c49610100836143e4565b90506000612c5961010084614493565b600092835260209490945250604090208054600190931b90921790915550565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612d0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610be2565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612da1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612de79190810190614088565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01611de5565b612e8a8282612f5b565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610be2565b6000612bf2828585604051602001612bd7919061413f565b6060612bf28484600085612f7f565b600082612f528584613115565b14949350505050565b6000806000612f6a8585613181565b91509150612f77816131ef565b509392505050565b606082471015613011576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610be2565b73ffffffffffffffffffffffffffffffffffffffff85163b61308f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610be2565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516130b891906144a7565b60006040518083038185875af1925050503d80600081146130f5576040519150601f19603f3d011682016040523d82523d6000602084013e6130fa565b606091505b509150915061310a828286613443565b979650505050505050565b600081815b8451811015612f7757600085828151811061313757613137613fb4565b6020026020010151905080831161315d576000838152602082905260409020925061316e565b600081815260208490526040902092505b5080613179816140e4565b91505061311a565b60008082516041036131b75760208301516040840151606085015160001a6131ab87828585613496565b945094505050506131e8565b82516040036131e057602083015160408401516131d58683836135ae565b9350935050506131e8565b506000905060025b9250929050565b6000816004811115613203576132036144c3565b0361320b5750565b600181600481111561321f5761321f6144c3565b03613286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610be2565b600281600481111561329a5761329a6144c3565b03613301576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610be2565b6003816004811115613315576133156144c3565b036133a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b60048160048111156133b6576133b66144c3565b0361070c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b606083156134525750816129f8565b8251156134625782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134cd57506000905060036135a5565b8460ff16601b141580156134e557508460ff16601c14155b156134f657506000905060046135a5565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561354a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661359e576000600192509250506135a5565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135e460ff86901c601b614220565b90506135f287828885613496565b935093505050935093915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461362457600080fd5b919050565b60006020828403121561363b57600080fd5b6129f882613600565b60006020828403121561365657600080fd5b5035919050565b801515811461070c57600080fd5b60008060006060848603121561368057600080fd5b61368984613600565b92506020840135915060408401356136a08161365d565b809150509250925092565b803563ffffffff8116811461362457600080fd5b6000602082840312156136d157600080fd5b6129f8826136ab565b600080604083850312156136ed57600080fd5b6136f683613600565b915061370460208401613600565b90509250929050565b803567ffffffffffffffff8116811461362457600080fd5b60008060008060008060c0878903121561373e57600080fd5b61374787613600565b955061375560208801613600565b945060408701359350606087013592506137716080880161370d565b915061377f60a088016136ab565b90509295509295509295565b6000806040838503121561379e57600080fd5b50508035926020909101359150565b600080604083850312156137c057600080fd5b6137c983613600565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156137f757600080fd5b6138008b613600565b995061380e60208c01613600565b985061381c60408c01613600565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061384660e08c0161370d565b92506138556101008c0161370d565b91506138646101208c016136ab565b90509295989b9194979a5092959850565b6000806020838503121561388857600080fd5b823567ffffffffffffffff808211156138a057600080fd5b818501915085601f8301126138b457600080fd5b8135818111156138c357600080fd5b8660208260051b85010111156138d857600080fd5b60209290920196919550909350505050565b60005b838110156139055781810151838201526020016138ed565b838111156117135750506000910152565b6000815180845261392e8160208601602086016138ea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139c1858351613916565b94509285019290850190600101613987565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a3257613a326139e0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7f57613a7f6139e0565b604052919050565b600067ffffffffffffffff821115613aa157613aa16139e0565b5060051b60200190565b600082601f830112613abc57600080fd5b81356020613ad1613acc83613a87565b613a38565b82815260059290921b84018101918181019086841115613af057600080fd5b8286015b84811015613b0b5780358352918301918301613af4565b509695505050505050565b600082601f830112613b2757600080fd5b81356020613b37613acc83613a87565b82815260059290921b84018101918181019086841115613b5657600080fd5b8286015b84811015613b0b57613b6b81613600565b8352918301918301613b5a565b600080600060608486031215613b8d57600080fd5b613b96846136ab565b9250602084013567ffffffffffffffff80821115613bb357600080fd5b9085019060c08288031215613bc757600080fd5b613bcf613a0f565b8235815260208301356020820152604083013582811115613bef57600080fd5b613bfb89828601613aab565b604083015250613c0d606084016136ab565b6060820152613c1e60808401613600565b608082015260a083013582811115613c3557600080fd5b613c4189828601613b16565b60a08301525093506040860135915080821115613c5d57600080fd5b50613c6a86828701613aab565b9150509250925092565b600067ffffffffffffffff821115613c8e57613c8e6139e0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613ccb57600080fd5b8135613cd9613acc82613c74565b818152846020838601011115613cee57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d2157600080fd5b613d2a85613600565b9350613d386020860161370d565b9250613d46604086016136ab565b9150606085013567ffffffffffffffff811115613d6257600080fd5b613d6e87828801613cba565b91505092959194509250565b6000806000806000806000806000806101408b8d031215613d9a57600080fd5b613da38b613600565b9950613db160208c01613600565b9850613dbf60408c01613600565b975060608b0135965060808b01359550613ddb60a08c0161370d565b9450613de960c08c0161370d565b9350613df760e08c016136ab565b9250613e066101008c016136ab565b91506101208b013567ffffffffffffffff811115613e2357600080fd5b613e2f8d828e01613aab565b9150509295989b9194979a5092959850565b6000806000806000806000806000806000806101808d8f031215613e6457600080fd5b613e6d8d613600565b9b50613e7b60208e01613600565b9a50613e8960408e01613600565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613eb360e08e0161370d565b9450613ec26101008e0161370d565b9350613ed16101208e0161370d565b9250613ee06101408e016136ab565b915067ffffffffffffffff6101608e01351115613efc57600080fd5b613f0d8e6101608f01358f01613cba565b90509295989b509295989b509295989b565b600060208284031215613f3157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f8457613f84613f38565b039392505050565b600063ffffffff808316818516808303821115613fab57613fab613f38565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261401857600080fd5b83018035915067ffffffffffffffff82111561403357600080fd5b6020019150368190038213156131e857600080fd5b8183823760009101908152919050565b6000614066613acc84613c74565b905082815283838301111561407a57600080fd5b6129f88360208301846138ea565b60006020828403121561409a57600080fd5b815167ffffffffffffffff8111156140b157600080fd5b8201601f810184136140c257600080fd5b612bf284825160208401614058565b6020815260006129f86020830184613916565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361411557614115613f38565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf26040830184613916565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516141b460c084018267ffffffffffffffff169052565b5060e08301516141d060e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613fab57613fab613f38565b60008282101561421b5761421b613f38565b500390565b6000821982111561423357614233613f38565b500190565b600063ffffffff80831681810361425157614251613f38565b6001019392505050565b600081518084526020808501945080840160005b8381101561428b5781518752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b8381101561428b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016142aa565b85815260a0602082015260006142f560a083018761425b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526143248287614296565b9250808516608085015250509695505050505050565b60006020828403121561434c57600080fd5b81516129f88161365d565b600067ffffffffffffffff83811690831681811015613f8457613f84613f38565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156143b0576143b0613f38565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826143f3576143f36143b5565b500490565b6020815281516020820152602082015160408201526000604083015160c0606084015261442860e084018261425b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526120a68282614296565b6000826144a2576144a26143b5565b500690565b600082516144b98184602087016138ea565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212200366289a2afa53961ee89e12be7aa19d0583eb8987acfd894558f08599d1737364736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806389a153cc116100f7578063daf9c21011610095578063ee2a53f811610064578063ee2a53f8146105e0578063f06850f614610615578063f500697c14610642578063ffc351a31461066257600080fd5b8063daf9c21014610530578063de7eba7814610573578063e190440214610593578063e282d5b9146105c057600080fd5b8063a1244c67116100d1578063a1244c671461048a578063ac9650d8146104c3578063c8356859146104e3578063c894c0ca1461051057600080fd5b806389a153cc146104375780638a7860ce146104575780639a8a05921461047757600080fd5b80633fc8cef3116101645780634e3485c81161013e5780634e3485c8146103555780635249fef1146103755780635285e058146103c057806357f6dcb8146103ed57600080fd5b80633fc8cef3146102ee5780634922897814610322578063493a4f841461033557600080fd5b8063272751c7116101a0578063272751c71461026b5780632752042e1461028b57806329cb924d146102ab578063364f01a6146102ce57600080fd5b80631c39c38d146101d25780631dfb2d021461022957806322f8e5661461024b57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506000546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023557600080fd5b50610249610244366004613629565b610682565b005b34801561025757600080fd5b50610249610266366004613644565b61070f565b34801561027757600080fd5b5061024961028636600461366b565b6107b8565b34801561029757600080fd5b506102496102a63660046136bf565b6108cf565b3480156102b757600080fd5b506102c06109d0565b604051908152602001610220565b3480156102da57600080fd5b506102496102e93660046136da565b610a88565b3480156102fa57600080fd5b506101ff7f000000000000000000000000000000000000000000000000000000000000000081565b610249610330366004613725565b610b17565b34801561034157600080fd5b5061024961035036600461378b565b610f7e565b34801561036157600080fd5b50610249610370366004613629565b6110a1565b34801561038157600080fd5b506103b06103903660046137ad565b600360209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610220565b3480156103cc57600080fd5b506001546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506002546104229074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610220565b34801561044357600080fd5b506102496104523660046137d7565b6110e7565b34801561046357600080fd5b50610249610472366004613644565b611243565b34801561048357600080fd5b50466102c0565b34801561049657600080fd5b50600254610422907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104d66104d1366004613875565b611317565b6040516102209190613960565b3480156104ef57600080fd5b506006546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561051c57600080fd5b5061024961052b366004613b78565b6114f1565b34801561053c57600080fd5b506101ff61054b366004613629565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b5061024961058e366004613629565b611575565b34801561059f57600080fd5b506002546101ff9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105cc57600080fd5b506102496105db366004613d0b565b6115bb565b3480156105ec57600080fd5b506106006105fb366004613644565b611719565b60408051928352602083019190915201610220565b34801561062157600080fd5b506102c0610630366004613644565b60056020526000908152604090205481565b34801561064e57600080fd5b5061024961065d366004613d7a565b611747565b34801561066e57600080fd5b5061024961067d366004613e41565b6117d3565b61068a61193e565b610692611a0a565b6106bf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611a8e565b61070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661073157600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561079d57600080fd5b505af11580156107b1573d6000803e3d6000fd5b5050505050565b6107c061193e565b6107c8611a0a565b6107f5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260036020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108d761193e565b6108df611a0a565b61090c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610a835760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7e9190613f1f565b905090565b504290565b610a9061193e565b610a98611a0a565b610ac5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610acf8282611b7a565b610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610b1f611a0a565b610b4c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832086845290915290205460ff16610beb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b600254610c919074010000000000000000000000000000000000000000900463ffffffff1682613f67565b63ffffffff16610c9f6109d0565b10158015610ce45750600254610cd39074010000000000000000000000000000000000000000900463ffffffff1682613f8c565b63ffffffff16610ce16109d0565b11155b610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610da55750600034115b15610e9957833414610e13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610be2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b5050505050610ebb565b610ebb73ffffffffffffffffffffffffffffffffffffffff8616333087611bf6565b610ef28446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611cd2565b6001600260188282829054906101000a900463ffffffff16610f149190613f8c565b92506101000a81548163ffffffff021916908363ffffffff160217905550610f76600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f8661193e565b610f8e611a0a565b610fbb600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60048054600181018255600091909152600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018490557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01828155604080518581526020810185905263ffffffff8416917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af910160405180910390a25050610b13600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6110a961193e565b6110b1611a0a565b6110de600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c881611d63565b6110ef611a0a565b61111c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111914690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111cd82611dd2565b905060006111df82848b886000611e02565b90506111f082828a888760006120af565b505050611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61124b61193e565b611253611a0a565b611280600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6004818154811061129357611293613fb4565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261070c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610be2565b8167ffffffffffffffff81111561139a5761139a6139e0565b6040519080825280602002602001820160405280156113cd57816020015b60608152602001906001900390816113b85790505b50905060005b828110156114ea57600080308686858181106113f1576113f1613fb4565b90506020028101906114039190613fe3565b604051611411929190614048565b600060405180830381855af49150503d806000811461144c576040519150601f19603f3d011682016040523d82523d6000602084013e611451565b606091505b5091509150816114b75760448151101561146a57600080fd5b600481019050808060200190518101906114849190614088565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b808484815181106114ca576114ca613fb4565b6020026020010181905250505080806114e2906140e4565b9150506113d3565b5092915050565b6114f9611a0a565b611526600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115318383836121e4565b6108ca600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61157d61193e565b611585611a0a565b6115b2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c8816125aa565b6115c3611a0a565b6115f0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610be2565b6116788446858585612696565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116c792919061411c565b60405180910390a3611713600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6004818154811061172957600080fd5b60009182526020909120600390910201805460019091015490915082565b61174f611a0a565b61177c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61178f8a8a8a8a8a468b8b8b8b8b612733565b611237600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6117db611a0a565b611808600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118158c87858585612696565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188a4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c682611dd2565b905060006118d882848d896000611e02565b90506118e982828c898760006120af565b505050611930600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b6001546119749073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610be2565b565b60005474010000000000000000000000000000000000000000900460ff16611a08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610be2565b73ffffffffffffffffffffffffffffffffffffffff8116611b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610be2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117139085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526128b2565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001611de5919061413f565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff16108015611e3a57506706f05b59d3b200008560c0015167ffffffffffffffff16105b611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610be2565b606085015160008781526005602052604090205410611f1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610be2565b83600003611f2b575060006120a6565b611f4484848760c00151611f3f91906141e6565b6129be565b60008781526005602052604081205460608801519293508692611f679190614209565b905082811015611f9057809250611f8d83868960c00151611f8891906141e6565b6129ff565b91505b60008881526005602052604081208054859290611fae908490614220565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361203657836120235760408701516120239073ffffffffffffffffffffffffffffffffffffffff16333085611bf6565b612031876020015183612a28565b6120a3565b8361207057612031338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611bf6909392919063ffffffff16565b6120a3876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f6040516121d49c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b46826020015114612251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610be2565b8160400151518260a0015151146122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610be2565b600060048463ffffffff16815481106122df576122df613fb4565b906000526020600020906003020190506122fe81600101548484612bbf565b612364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610be2565b61237b81600201846060015163ffffffff16612bfa565b156123e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610be2565b6123f981600201846060015163ffffffff16612c3b565b60005b8360400151518163ffffffff1610156124a557600084604001518263ffffffff168151811061242d5761242d613fb4565b602002602001015190506000811115612492576124928560a001518363ffffffff168151811061245f5761245f613fb4565b602002602001015182876080015173ffffffffffffffffffffffffffffffffffffffff16612b699092919063ffffffff16565b508061249d81614238565b9150506123fc565b5082511561253e576124b683612c79565b826080015173ffffffffffffffffffffffffffffffffffffffff16836060015163ffffffff1684602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f7186600001513360405161253592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b826060015163ffffffff168463ffffffff1684602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8660000151876040015188608001518960a001513360405161259c9594939291906142dc565b60405180910390a450505050565b73ffffffffffffffffffffffffffffffffffffffff8116612627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610be2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061271d82612e45565b905061272a878285612e80565b50505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061280860048463ffffffff16815481106127ef576127ef613fb4565b9060005260206000209060030201600001548284612f1e565b61286e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610be2565b600061287982611dd2565b905060006128908284856060015160006001611e02565b90506128a282826000808760016120af565b5050505050505050505050505050565b6000612914826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f369092919063ffffffff16565b8051909150156108ca5780806020019051810190612932919061433a565b6108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610be2565b60006129d282670de0b6b3a7640000614357565b67ffffffffffffffff166129ee84670de0b6b3a7640000614378565b6129f891906143e4565b9392505050565b6000670de0b6b3a7640000612a148382614357565b6129ee9067ffffffffffffffff1685614378565b73ffffffffffffffffffffffffffffffffffffffff82163b15612a8657610b1373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612b69565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b0e57600080fd5b505af1158015612b22573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ca573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ca9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c50565b6000612bf2828585604051602001612bd791906143f8565b60405160208183030381529060405280519060200120612f45565b949350505050565b600080612c09610100846143e4565b90506000612c1961010085614493565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c49610100836143e4565b90506000612c5961010084614493565b600092835260209490945250604090208054600190931b90921790915550565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612d0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610be2565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612da1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612de79190810190614088565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01611de5565b612e8a8282612f5b565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610be2565b6000612bf2828585604051602001612bd7919061413f565b6060612bf28484600085612f7f565b600082612f528584613115565b14949350505050565b6000806000612f6a8585613181565b91509150612f77816131ef565b509392505050565b606082471015613011576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610be2565b73ffffffffffffffffffffffffffffffffffffffff85163b61308f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610be2565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516130b891906144a7565b60006040518083038185875af1925050503d80600081146130f5576040519150601f19603f3d011682016040523d82523d6000602084013e6130fa565b606091505b509150915061310a828286613443565b979650505050505050565b600081815b8451811015612f7757600085828151811061313757613137613fb4565b6020026020010151905080831161315d576000838152602082905260409020925061316e565b600081815260208490526040902092505b5080613179816140e4565b91505061311a565b60008082516041036131b75760208301516040840151606085015160001a6131ab87828585613496565b945094505050506131e8565b82516040036131e057602083015160408401516131d58683836135ae565b9350935050506131e8565b506000905060025b9250929050565b6000816004811115613203576132036144c3565b0361320b5750565b600181600481111561321f5761321f6144c3565b03613286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610be2565b600281600481111561329a5761329a6144c3565b03613301576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610be2565b6003816004811115613315576133156144c3565b036133a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b60048160048111156133b6576133b66144c3565b0361070c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610be2565b606083156134525750816129f8565b8251156134625782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610be291906140d1565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134cd57506000905060036135a5565b8460ff16601b141580156134e557508460ff16601c14155b156134f657506000905060046135a5565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561354a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661359e576000600192509250506135a5565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135e460ff86901c601b614220565b90506135f287828885613496565b935093505050935093915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461362457600080fd5b919050565b60006020828403121561363b57600080fd5b6129f882613600565b60006020828403121561365657600080fd5b5035919050565b801515811461070c57600080fd5b60008060006060848603121561368057600080fd5b61368984613600565b92506020840135915060408401356136a08161365d565b809150509250925092565b803563ffffffff8116811461362457600080fd5b6000602082840312156136d157600080fd5b6129f8826136ab565b600080604083850312156136ed57600080fd5b6136f683613600565b915061370460208401613600565b90509250929050565b803567ffffffffffffffff8116811461362457600080fd5b60008060008060008060c0878903121561373e57600080fd5b61374787613600565b955061375560208801613600565b945060408701359350606087013592506137716080880161370d565b915061377f60a088016136ab565b90509295509295509295565b6000806040838503121561379e57600080fd5b50508035926020909101359150565b600080604083850312156137c057600080fd5b6137c983613600565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156137f757600080fd5b6138008b613600565b995061380e60208c01613600565b985061381c60408c01613600565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061384660e08c0161370d565b92506138556101008c0161370d565b91506138646101208c016136ab565b90509295989b9194979a5092959850565b6000806020838503121561388857600080fd5b823567ffffffffffffffff808211156138a057600080fd5b818501915085601f8301126138b457600080fd5b8135818111156138c357600080fd5b8660208260051b85010111156138d857600080fd5b60209290920196919550909350505050565b60005b838110156139055781810151838201526020016138ed565b838111156117135750506000910152565b6000815180845261392e8160208601602086016138ea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139d3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139c1858351613916565b94509285019290850190600101613987565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a3257613a326139e0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7f57613a7f6139e0565b604052919050565b600067ffffffffffffffff821115613aa157613aa16139e0565b5060051b60200190565b600082601f830112613abc57600080fd5b81356020613ad1613acc83613a87565b613a38565b82815260059290921b84018101918181019086841115613af057600080fd5b8286015b84811015613b0b5780358352918301918301613af4565b509695505050505050565b600082601f830112613b2757600080fd5b81356020613b37613acc83613a87565b82815260059290921b84018101918181019086841115613b5657600080fd5b8286015b84811015613b0b57613b6b81613600565b8352918301918301613b5a565b600080600060608486031215613b8d57600080fd5b613b96846136ab565b9250602084013567ffffffffffffffff80821115613bb357600080fd5b9085019060c08288031215613bc757600080fd5b613bcf613a0f565b8235815260208301356020820152604083013582811115613bef57600080fd5b613bfb89828601613aab565b604083015250613c0d606084016136ab565b6060820152613c1e60808401613600565b608082015260a083013582811115613c3557600080fd5b613c4189828601613b16565b60a08301525093506040860135915080821115613c5d57600080fd5b50613c6a86828701613aab565b9150509250925092565b600067ffffffffffffffff821115613c8e57613c8e6139e0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613ccb57600080fd5b8135613cd9613acc82613c74565b818152846020838601011115613cee57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d2157600080fd5b613d2a85613600565b9350613d386020860161370d565b9250613d46604086016136ab565b9150606085013567ffffffffffffffff811115613d6257600080fd5b613d6e87828801613cba565b91505092959194509250565b6000806000806000806000806000806101408b8d031215613d9a57600080fd5b613da38b613600565b9950613db160208c01613600565b9850613dbf60408c01613600565b975060608b0135965060808b01359550613ddb60a08c0161370d565b9450613de960c08c0161370d565b9350613df760e08c016136ab565b9250613e066101008c016136ab565b91506101208b013567ffffffffffffffff811115613e2357600080fd5b613e2f8d828e01613aab565b9150509295989b9194979a5092959850565b6000806000806000806000806000806000806101808d8f031215613e6457600080fd5b613e6d8d613600565b9b50613e7b60208e01613600565b9a50613e8960408e01613600565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613eb360e08e0161370d565b9450613ec26101008e0161370d565b9350613ed16101208e0161370d565b9250613ee06101408e016136ab565b915067ffffffffffffffff6101608e01351115613efc57600080fd5b613f0d8e6101608f01358f01613cba565b90509295989b509295989b509295989b565b600060208284031215613f3157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f8457613f84613f38565b039392505050565b600063ffffffff808316818516808303821115613fab57613fab613f38565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261401857600080fd5b83018035915067ffffffffffffffff82111561403357600080fd5b6020019150368190038213156131e857600080fd5b8183823760009101908152919050565b6000614066613acc84613c74565b905082815283838301111561407a57600080fd5b6129f88360208301846138ea565b60006020828403121561409a57600080fd5b815167ffffffffffffffff8111156140b157600080fd5b8201601f810184136140c257600080fd5b612bf284825160208401614058565b6020815260006129f86020830184613916565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361411557614115613f38565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf26040830184613916565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516141b460c084018267ffffffffffffffff169052565b5060e08301516141d060e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613fab57613fab613f38565b60008282101561421b5761421b613f38565b500390565b6000821982111561423357614233613f38565b500190565b600063ffffffff80831681810361425157614251613f38565b6001019392505050565b600081518084526020808501945080840160005b8381101561428b5781518752958201959082019060010161426f565b509495945050505050565b600081518084526020808501945080840160005b8381101561428b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016142aa565b85815260a0602082015260006142f560a083018761425b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526143248287614296565b9250808516608085015250509695505050505050565b60006020828403121561434c57600080fd5b81516129f88161365d565b600067ffffffffffffffff83811690831681811015613f8457613f84613f38565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156143b0576143b0613f38565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826143f3576143f36143b5565b500490565b6020815281516020820152602082015160408201526000604083015160c0606084015261442860e084018261425b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526120a68282614296565b6000826144a2576144a26143b5565b500690565b600082516144b98184602087016138ea565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212200366289a2afa53961ee89e12be7aa19d0583eb8987acfd894558f08599d1737364736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json b/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json index c559e7d2..dfb09219 100644 --- a/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json +++ b/deployments/arbitrum-rinkeby/solcInputs/c8b9349311d8b5049b613ac98eb998d0.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 chainId_;\n\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {}\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {}\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"OVM_XCHAIN: messenger contract unauthenticated\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,34 +113,34 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 5_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.1e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 10e9; // 10 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20Gateway;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20Gateway ERC20 gateway contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20Gateway) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20Gateway = _l1ERC20Gateway;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n l1ERC20Gateway.outboundTransfer(l1Token, to, amount, l2GasLimit, l2GasPrice, \"\");\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 5_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.1e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 10e9; // 10 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20Gateway;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20Gateway ERC20 gateway contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20Gateway) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20Gateway = _l1ERC20Gateway;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n l1ERC20Gateway.outboundTransfer(l1Token, to, amount, l2GasLimit, l2GasPrice, \"\");\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -149,25 +149,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/arbitrum/Arbitrum_SpokePool.json b/deployments/arbitrum/Arbitrum_SpokePool.json index 0cb3c206..9ef1fd8a 100644 --- a/deployments/arbitrum/Arbitrum_SpokePool.json +++ b/deployments/arbitrum/Arbitrum_SpokePool.json @@ -1206,7 +1206,7 @@ ], "numDeployments": 1, "solcInputHash": "1a5892b796c4f5bdf21d8cd0d15027f4", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"}],\"name\":\"ArbitrumTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"SetL2GatewayRouter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"WhitelistedTokens\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GatewayRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newL2GatewayRouter\",\"type\":\"address\"}],\"name\":\"setL2GatewayRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"whitelistToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_l2GatewayRouter\":\"Address of L2 token gateway. Can be reset by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL2GatewayRouter(address)\":{\"params\":{\"newL2GatewayRouter\":\"New L2 gateway router.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"whitelistToken(address,address)\":{\"params\":{\"l1Token\":\"Ethereum version of l2Token.\",\"l2Token\":\"Arbitrum token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the AVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL2GatewayRouter(address)\":{\"notice\":\"Change L2 gateway router. Callable only by admin.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"whitelistToken(address,address)\":{\"notice\":\"Add L2 -> L1 token mapping. Callable only by admin.\"}},\"notice\":\"AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Arbitrum_SpokePool.sol\":\"Arbitrum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Arbitrum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\n\\ninterface StandardBridgeLike {\\n function outboundTransfer(\\n address _l1Token,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n}\\n\\n/**\\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Arbitrum_SpokePool is SpokePool {\\n // Address of the Arbitrum L2 token gateway to send funds to L1.\\n address public l2GatewayRouter;\\n\\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\\n // are necessary params used when bridging tokens to L1.\\n mapping(address => address) public whitelistedTokens;\\n\\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\\n\\n /**\\n * @notice Construct the AVM SpokePool.\\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _l2GatewayRouter,\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\\n _setL2GatewayRouter(_l2GatewayRouter);\\n }\\n\\n modifier onlyFromCrossDomainAdmin() {\\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \\\"ONLY_COUNTERPART_GATEWAY\\\");\\n _;\\n }\\n\\n /********************************************************\\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\n ********************************************************/\\n\\n /**\\n * @notice Change L2 gateway router. Callable only by admin.\\n * @param newL2GatewayRouter New L2 gateway router.\\n */\\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\\n _setL2GatewayRouter(newL2GatewayRouter);\\n }\\n\\n /**\\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\\n * @param l2Token Arbitrum token.\\n * @param l1Token Ethereum version of l2Token.\\n */\\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\\n _whitelistToken(l2Token, l1Token);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\\n require(ethereumTokenToBridge != address(0), \\\"Uninitialized mainnet token\\\");\\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\\n l2GatewayRouter = _l2GatewayRouter;\\n emit SetL2GatewayRouter(l2GatewayRouter);\\n }\\n\\n function _whitelistToken(address _l2Token, address _l1Token) internal {\\n whitelistedTokens[_l2Token] = _l1Token;\\n emit WhitelistedTokens(_l2Token, _l1Token);\\n }\\n\\n // L1 addresses are transformed during l1->l2 calls.\\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\\n // Allows overflows as explained above.\\n unchecked {\\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\\n }\\n }\\n\\n // Apply AVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\\n}\\n\",\"keccak256\":\"0xc268f7713116a22b39308cbf93decd4dfba223801a0013bb088aa8209d588234\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200482a3803806200482a8339810160408190526200004a916200025a565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055838383836200007a84620000ab565b620000858362000151565b506001600160a01b031660805250620000a0905085620001f3565b5050505050620002ca565b6001600160a01b038116620001075760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a95760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fe565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b0319166001600160a01b0383169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b80516001600160a01b03811681146200025557600080fd5b919050565b600080600080600060a086880312156200027357600080fd5b6200027e866200023d565b94506200028e602087016200023d565b93506200029e604087016200023d565b9250620002ae606087016200023d565b9150620002be608087016200023d565b90509295509295909350565b60805161452162000309600039600081816101e401528181610dd001528181610e990152818161237e01528181612d2c0152612d8201526145216000f3fe6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101c65760003560e01c806357f6dcb8116100f7578063c835685911610095578063e282d5b911610064578063e282d5b9146105e0578063ee2a53f814610600578063f06850f614610635578063ffc351a31461066257600080fd5b8063c835685914610523578063daf9c21014610550578063de7eba7814610593578063e1904402146105b357600080fd5b80639a8a0592116100d15780639a8a059214610497578063a1244c67146104aa578063ac9650d8146104e3578063be3576ee1461050357600080fd5b806357f6dcb81461040d57806389a153cc146104575780638a7860ce1461047757600080fd5b806329cb924d11610164578063493a4f841161013e578063493a4f84146103555780634e3485c8146103755780635249fef1146103955780635285e058146103e057600080fd5b806329cb924d146102ff578063364f01a614610322578063492289781461034257600080fd5b80631dfb2d02116101a05780631dfb2d021461027f57806322f8e5661461029f578063272751c7146102bf5780632752042e146102df57600080fd5b806317fcb39b146101d25780631b3d5559146102305780631c39c38d1461025257600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506102067f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023c57600080fd5b5061025061024b3660046137c6565b610682565b005b34801561025e57600080fd5b506000546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028b57600080fd5b5061025061029a3660046138c2565b61070b565b3480156102ab57600080fd5b506102506102ba3660046138dd565b610798565b3480156102cb57600080fd5b506102506102da366004613904565b610841565b3480156102eb57600080fd5b506102506102fa366004613944565b610953565b34801561030b57600080fd5b50610314610a54565b604051908152602001610227565b34801561032e57600080fd5b5061025061033d36600461395f565b610b0c565b6102506103503660046139aa565b610b9b565b34801561036157600080fd5b50610250610370366004613a10565b611012565b34801561038157600080fd5b506102506103903660046138c2565b611128565b3480156103a157600080fd5b506103d06103b0366004613a32565b600460209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610227565b3480156103ec57600080fd5b506001546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561041957600080fd5b506002546104429074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610227565b34801561046357600080fd5b50610250610472366004613a5c565b61116e565b34801561048357600080fd5b506102506104923660046138dd565b6112ca565b3480156104a357600080fd5b5046610314565b3480156104b657600080fd5b50600254610442907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104f66104f1366004613afa565b61139e565b6040516102279190613be5565b34801561050f57600080fd5b5061025061051e366004613c65565b611578565b34801561052f57600080fd5b506006546102069073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055c57600080fd5b5061020661056b3660046138c2565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059f57600080fd5b506102506105ae3660046138c2565b611604565b3480156105bf57600080fd5b506002546102069073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ec57600080fd5b506102506105fb366004613dc3565b61164a565b34801561060c57600080fd5b5061062061061b3660046138dd565b6117a8565b60408051928352602083019190915201610227565b34801561064157600080fd5b506103146106503660046138dd565b60056020526000908152604090205481565b34801561066e57600080fd5b5061025061067d366004613e32565b6117d6565b61068a611941565b6106b7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106c28383836119c7565b610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610713611d73565b61071b611941565b610748600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181611e3d565b610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff166107ba57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561082657600080fd5b505af115801561083a573d6000803e3d6000fd5b5050505050565b610849611d73565b610851611941565b61087e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610706600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61095b611d73565b610963611941565b610990600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a1610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610b075760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190613f10565b905090565b504290565b610b14611d73565b610b1c611941565b610b49600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610b538282611f29565b610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b610ba3611941565b610bd0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610c6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610cea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b600254610d159074010000000000000000000000000000000000000000900463ffffffff1682613f58565b63ffffffff16610d23610a54565b10158015610d685750600254610d579074010000000000000000000000000000000000000000900463ffffffff1682613f7d565b63ffffffff16610d65610a54565b11155b610dce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610e295750600034115b15610f1d57833414610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610c66565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610eff57600080fd5b505af1158015610f13573d6000803e3d6000fd5b5050505050610f3f565b610f3f73ffffffffffffffffffffffffffffffffffffffff8616333087611fa5565b610f768446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612081565b60028054601890610fa8907801000000000000000000000000000000000000000000000000900463ffffffff16613fa5565b91906101000a81548163ffffffff021916908363ffffffff16021790555061100a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b61101a611d73565b611022611941565b61104f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050610b97600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611130611d73565b611138611941565b611165600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61075181612112565b611176611941565b6111a3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112184690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061125482612181565b9050600061126682848b8860006121b1565b905061127782828a8887600061245e565b5050506112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6112d2611d73565b6112da611941565b611307600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061131a5761131a613fc8565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a2610795600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611408576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610c66565b8167ffffffffffffffff8111156114215761142161360a565b60405190808252806020026020018201604052801561145457816020015b606081526020019060019003908161143f5790505b50905060005b82811015611571576000803086868581811061147857611478613fc8565b905060200281019061148a9190613ff7565b60405161149892919061405c565b600060405180830381855af49150503d80600081146114d3576040519150601f19603f3d011682016040523d82523d6000602084013e6114d8565b606091505b50915091508161153e576044815110156114f157600080fd5b6004810190508080602001905181019061150b919061409c565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b8084848151811061155157611551613fc8565b60200260200101819052505050808061156990614100565b91505061145a565b5092915050565b611580611941565b6115ad600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115c08a8a8a8a8a468b8b8b8b8b6125a0565b6112be600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61160c611d73565b611614611941565b611641600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107518161271f565b611652611941565b61167f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106116fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610c66565b611707844685858561280b565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611756929190614138565b60405180910390a36117a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106117b857600080fd5b60009182526020909120600390910201805460019091015490915082565b6117de611941565b61180b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118188c8785858561280b565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161188d4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff16815250905060006118c982612181565b905060006118db82848d8960006121b1565b90506118ec82828c8987600061245e565b505050611933600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c66565b565b46826020015114611a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610c66565b8160400151518260a001515114611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610c66565b600060038463ffffffff1681548110611ac257611ac2613fc8565b90600052602060002090600302019050611ae1816001015484846128a8565b611b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610c66565b611b5e81600201846060015163ffffffff166128e5565b15611bc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610c66565b611bdc81600201846060015163ffffffff16612926565b60408301515160005b81811015611c6d57600085604001518281518110611c0557611c05613fc8565b602002602001015190506000811115611c6457611c648660a001518381518110611c3157611c31613fc8565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50600101611be5565b50835115611d0657611c7e846129ba565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611cfd92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611d649594939291906141dc565b60405180910390a45050505050565b600154611da99073ffffffffffffffffffffffffffffffffffffffff167311110000000000000000000000000000000011110190565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f4e4c595f434f554e544552504152545f4741544557415900000000000000006044820152606401610c66565b73ffffffffffffffffffffffffffffffffffffffff8116611eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610c66565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526007602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8d7f294eaa476236fe8cb5629376a12cd37dace3d21e6a7b98f1641c4ed5f09e9190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117a29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b86565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fdc4a5f4c066ad14c1306e624550b42395e08f992a76b416cc7b1ad11503d376c90600090a250565b600081604051602001612194919061423a565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121e957506706f05b59d3b200008560c0015167ffffffffffffffff16105b61224f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610c66565b6060850151600087815260056020526040902054106122ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610c66565b836000036122da57506000612455565b6122f384848760c001516122ee91906142e1565b612c92565b600087815260056020526040812054606088015192935086926123169190614304565b90508281101561233f5780925061233c83868960c0015161233791906142e1565b612ccc565b91505b6000888152600560205260408120805485929061235d90849061431b565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123e557836123d25760408701516123d29073ffffffffffffffffffffffffffffffffffffffff16333085611fa5565b6123e0876020015183612cf5565b612452565b8361241f576123e0338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611fa5909392919063ffffffff16565b612452876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129649092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516125909d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061267560038463ffffffff168154811061265c5761265c613fc8565b9060005260206000209060030201600001548284612e36565b6126db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610c66565b60006126e682612181565b905060006126fd82848560600151600060016121b1565b905061270f828260008087600161245e565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661279c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610c66565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061289282612e4e565b905061289f878285612e89565b50505050505050565b60006128db8285856040516020016128c09190614333565b60405160208183030381529060405280519060200120612f27565b90505b9392505050565b6000806128f4610100846143fd565b9050600061290461010085614411565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612934610100836143fd565b9050600061294461010084614411565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526107069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fff565b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541680612a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f556e696e697469616c697a6564206d61696e6e657420746f6b656e00000000006044820152606401610c66565b60065460025483516040517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152928316602482015260448101919091526080606482015260006084820152911690637b3a3c8b9060a4016000604051808303816000875af1158015612ae2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b28919081019061409c565b5060025482516040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526000917f997d81a0a8415d688a6c319736602098252bf6445e0e879326f682f11928e317910160405180910390a25050565b6000612be8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612f3d9092919063ffffffff16565b8051909150156107065780806020019051810190612c069190614425565b610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c66565b6000612ca682670de0b6b3a7640000614442565b67ffffffffffffffff16612cc284670de0b6b3a7640000614463565b6128de91906143fd565b6000670de0b6b3a7640000612ce18382614442565b612cc29067ffffffffffffffff1685614463565b73ffffffffffffffffffffffffffffffffffffffff82163b15612d5357610b9773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612964565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612ddb57600080fd5b505af1158015612def573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610706573d6000803e3d6000fd5b60006128db8285856040516020016128c0919061423a565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612194565b612e938282612f4c565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610c66565b600082612f348584612f70565b14949350505050565b60606128db8484600085612fdc565b6000806000612f5b8585613172565b91509150612f68816131e0565b509392505050565b600081815b8451811015612f68576000858281518110612f9257612f92613fc8565b60200260200101519050808311612fb85760008381526020829052604090209250612fc9565b600081815260208490526040902092505b5080612fd481614100565b915050612f75565b60608247101561306e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c66565b73ffffffffffffffffffffffffffffffffffffffff85163b6130ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c66565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161311591906144a0565b60006040518083038185875af1925050503d8060008114613152576040519150601f19603f3d011682016040523d82523d6000602084013e613157565b606091505b5091509150613167828286613434565b979650505050505050565b60008082516041036131a85760208301516040840151606085015160001a61319c87828585613487565b945094505050506131d9565b82516040036131d157602083015160408401516131c686838361359f565b9350935050506131d9565b506000905060025b9250929050565b60008160048111156131f4576131f46144bc565b036131fc5750565b6001816004811115613210576132106144bc565b03613277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610c66565b600281600481111561328b5761328b6144bc565b036132f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610c66565b6003816004811115613306576133066144bc565b03613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b60048160048111156133a7576133a76144bc565b03610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610c66565b606083156134435750816128de565b8251156134535782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6691906140ed565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156134be5750600090506003613596565b8460ff16601b141580156134d657508460ff16601c14155b156134e75750600090506004613596565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561353b573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661358f57600060019250925050613596565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816135d560ff86901c601b61431b565b90506135e387828885613487565b935093505050935093915050565b803563ffffffff8116811461360557600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561365c5761365c61360a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156136a9576136a961360a565b604052919050565b600067ffffffffffffffff8211156136cb576136cb61360a565b5060051b60200190565b600082601f8301126136e657600080fd5b813560206136fb6136f6836136b1565b613662565b82815260059290921b8401810191818101908684111561371a57600080fd5b8286015b84811015613735578035835291830191830161371e565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461360557600080fd5b600082601f83011261377557600080fd5b813560206137856136f6836136b1565b82815260059290921b840181019181810190868411156137a457600080fd5b8286015b84811015613735576137b981613740565b83529183019183016137a8565b6000806000606084860312156137db57600080fd5b6137e4846135f1565b9250602084013567ffffffffffffffff8082111561380157600080fd5b9085019060c0828803121561381557600080fd5b61381d613639565b823581526020830135602082015260408301358281111561383d57600080fd5b613849898286016136d5565b60408301525061385b606084016135f1565b606082015261386c60808401613740565b608082015260a08301358281111561388357600080fd5b61388f89828601613764565b60a083015250935060408601359150808211156138ab57600080fd5b506138b8868287016136d5565b9150509250925092565b6000602082840312156138d457600080fd5b6128de82613740565b6000602082840312156138ef57600080fd5b5035919050565b801515811461079557600080fd5b60008060006060848603121561391957600080fd5b61392284613740565b9250602084013591506040840135613939816138f6565b809150509250925092565b60006020828403121561395657600080fd5b6128de826135f1565b6000806040838503121561397257600080fd5b61397b83613740565b915061398960208401613740565b90509250929050565b803567ffffffffffffffff8116811461360557600080fd5b60008060008060008060c087890312156139c357600080fd5b6139cc87613740565b95506139da60208801613740565b945060408701359350606087013592506139f660808801613992565b9150613a0460a088016135f1565b90509295509295509295565b60008060408385031215613a2357600080fd5b50508035926020909101359150565b60008060408385031215613a4557600080fd5b613a4e83613740565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613a7c57600080fd5b613a858b613740565b9950613a9360208c01613740565b9850613aa160408c01613740565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613acb60e08c01613992565b9250613ada6101008c01613992565b9150613ae96101208c016135f1565b90509295989b9194979a5092959850565b60008060208385031215613b0d57600080fd5b823567ffffffffffffffff80821115613b2557600080fd5b818501915085601f830112613b3957600080fd5b813581811115613b4857600080fd5b8660208260051b8501011115613b5d57600080fd5b60209290920196919550909350505050565b60005b83811015613b8a578181015183820152602001613b72565b838111156117a25750506000910152565b60008151808452613bb3816020860160208601613b6f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613c58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613c46858351613b9b565b94509285019290850190600101613c0c565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613c8557600080fd5b613c8e8b613740565b9950613c9c60208c01613740565b9850613caa60408c01613740565b975060608b0135965060808b01359550613cc660a08c01613992565b9450613cd460c08c01613992565b9350613ce260e08c016135f1565b9250613cf16101008c016135f1565b91506101208b013567ffffffffffffffff811115613d0e57600080fd5b613d1a8d828e016136d5565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613d4657613d4661360a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613d8357600080fd5b8135613d916136f682613d2c565b818152846020838601011115613da657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613dd957600080fd5b613de285613740565b9350613df060208601613992565b9250613dfe604086016135f1565b9150606085013567ffffffffffffffff811115613e1a57600080fd5b613e2687828801613d72565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613e5557600080fd5b613e5e8d613740565b9b50613e6c60208e01613740565b9a50613e7a60408e01613740565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613ea460e08e01613992565b9450613eb36101008e01613992565b9350613ec26101208e01613992565b9250613ed16101408e016135f1565b915067ffffffffffffffff6101608e01351115613eed57600080fd5b613efe8e6101608f01358f01613d72565b90509295989b509295989b509295989b565b600060208284031215613f2257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613f7557613f75613f29565b039392505050565b600063ffffffff808316818516808303821115613f9c57613f9c613f29565b01949350505050565b600063ffffffff808316818103613fbe57613fbe613f29565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261402c57600080fd5b83018035915067ffffffffffffffff82111561404757600080fd5b6020019150368190038213156131d957600080fd5b8183823760009101908152919050565b600061407a6136f684613d2c565b905082815283838301111561408e57600080fd5b6128de836020830184613b6f565b6000602082840312156140ae57600080fd5b815167ffffffffffffffff8111156140c557600080fd5b8201601f810184136140d657600080fd5b6140e58482516020840161406c565b949350505050565b6020815260006128de6020830184613b9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361413157614131613f29565b5060010190565b67ffffffffffffffff831681526040602082015260006128db6040830184613b9b565b600081518084526020808501945080840160005b8381101561418b5781518752958201959082019060010161416f565b509495945050505050565b600081518084526020808501945080840160005b8381101561418b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141aa565b85815260a0602082015260006141f560a083018761415b565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526142248287614196565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516142af60c084018267ffffffffffffffff169052565b5060e08301516142cb60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613f9c57613f9c613f29565b60008282101561431657614316613f29565b500390565b6000821982111561432e5761432e613f29565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261436360e084018261415b565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124558282614196565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261440c5761440c6143ce565b500490565b600082614420576144206143ce565b500690565b60006020828403121561443757600080fd5b81516128de816138f6565b600067ffffffffffffffff83811690831681811015613f7557613f75613f29565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449b5761449b613f29565b500290565b600082516144b2818460208701613b6f565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220824fd71e31f6f23b9cad96da1db93c08eb986fdd4ea50840024056d9e4ecfab764736f6c634300080d0033", "devdoc": { diff --git a/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json b/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json index 021d97dd..b2008943 100644 --- a/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json +++ b/deployments/arbitrum/solcInputs/1a5892b796c4f5bdf21d8cd0d15027f4.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n timerAddress,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n timerAddress,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/boba/Boba_SpokePool.json b/deployments/boba/Boba_SpokePool.json index 32bc45dc..00a7c160 100644 --- a/deployments/boba/Boba_SpokePool.json +++ b/deployments/boba/Boba_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "4d00864cb95f68f23bc763892eeb3451", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Boba SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Boba_SpokePool.sol\":\"Boba_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Boba_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\\r\\n */\\r\\ncontract Boba_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Boba SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x294baa3e6cad689a274156221f025eec942a8115307167c652384200d92b6d11\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Boba SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Boba_SpokePool.sol\":\"Boba_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Boba_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\\r\\n */\\r\\ncontract Boba_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Boba SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x294baa3e6cad689a274156221f025eec942a8115307167c652384200d92b6d11\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b401790553480156200003b57600080fd5b5060405162004c9738038062004c978339810160408190526200005e9162000277565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273420000000000000000000000000000000000000673deaddeaddeaddeaddeaddeaddeaddeaddead00008484848383620000e18462000112565b620000ec83620001b8565b506001600160a01b039081166080529490941660a05250620002c1975050505050505050565b6001600160a01b0381166200016e5760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002105760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000165565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200027257600080fd5b919050565b6000806000606084860312156200028d57600080fd5b62000298846200025a565b9250620002a8602085016200025a565b9150620002b8604085016200025a565b90509250925092565b60805160a05161496a6200032d600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220eb7c71015621a3f0e8435e96b853ec4cb7e61d884a87ee1833c41a0d61e5854664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220eb7c71015621a3f0e8435e96b853ec4cb7e61d884a87ee1833c41a0d61e5854664736f6c634300080d0033", "devdoc": { diff --git a/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json b/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json index 909d1e83..4fc72aca 100644 --- a/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json +++ b/deployments/boba/solcInputs/4d00864cb95f68f23bc763892eeb3451.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 43633ef5..9303e25d 100644 --- a/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/boba/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/goerli/AcrossConfigStore.json b/deployments/goerli/AcrossConfigStore.json index 52bc7404..938dc2bc 100644 --- a/deployments/goerli/AcrossConfigStore.json +++ b/deployments/goerli/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "e3638a53e1e5b7b0c7a6b5bbdc94b1ad", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbd4b1690b7d56f2fd7b61f3b9022c6b856c7dfee5a5aca547cf1403b906fdc0d\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\n * to be consumed by off-chain bots, rather than by other contracts.\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\n * system of the full contract suite..\\n */\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\n // Transfer Thresholds.\\n mapping(address => string) public l1TokenConfig;\\n\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\n mapping(bytes32 => string) public globalConfig;\\n\\n event UpdatedTokenConfig(address indexed key, string value);\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\n\\n /**\\n * @notice Updates token config.\\n * @param l1Token the l1 token address to update value for.\\n * @param value Value to update.\\n */\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\n l1TokenConfig[l1Token] = value;\\n emit UpdatedTokenConfig(l1Token, value);\\n }\\n\\n /**\\n * @notice Updates global config.\\n * @param key Key to update.\\n * @param value Value to update.\\n */\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\n globalConfig[key] = value;\\n emit UpdatedGlobalConfig(key, value);\\n }\\n}\\n\",\"keccak256\":\"0xacaa65ede2dcee0a24fd5d9940914c364be7e988f89cdaea1386e0474d51f6f7\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbd4b1690b7d56f2fd7b61f3b9022c6b856c7dfee5a5aca547cf1403b906fdc0d\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\n * to be consumed by off-chain bots, rather than by other contracts.\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\n * system of the full contract suite..\\n */\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\n // Transfer Thresholds.\\n mapping(address => string) public l1TokenConfig;\\n\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\n mapping(bytes32 => string) public globalConfig;\\n\\n event UpdatedTokenConfig(address indexed key, string value);\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\n\\n /**\\n * @notice Updates token config.\\n * @param l1Token the l1 token address to update value for.\\n * @param value Value to update.\\n */\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\n l1TokenConfig[l1Token] = value;\\n emit UpdatedTokenConfig(l1Token, value);\\n }\\n\\n /**\\n * @notice Updates global config.\\n * @param key Key to update.\\n * @param value Value to update.\\n */\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\n globalConfig[key] = value;\\n emit UpdatedGlobalConfig(key, value);\\n }\\n}\\n\",\"keccak256\":\"0xacaa65ede2dcee0a24fd5d9940914c364be7e988f89cdaea1386e0474d51f6f7\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080806040523461005b5760008054336001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361100090816100618239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c90816350fbbd011461009a57508063715018a6146100955780638098b875146100905780638da5cb5b1461008b5780639fdd403a14610086578063ac9650d814610081578063e5e818ae1461007c5763f2fde38b1461007757600080fd5b610926565b610729565b6105e0565b610502565b6104b0565b610413565b61033c565b3461010d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d576100fd60406101099273ffffffffffffffffffffffffffffffffffffffff6100ef610110565b168152600160205220610200565b6040519182918261032b565b0390f35b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b600080fd5b90600182811c92168015610181575b602083101461015257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610147565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101fb57604052565b61018b565b6040519081600082549261021384610138565b9081845260019485811690816000146102835750600114610240575b505061023d925003826101ba565b90565b9093915060005260209081600020936000915b81831061026b57505061023d9350820101388061022f565b85548784018501529485019486945091830191610253565b905061023d9550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101388061022f565b60005b8381106102d85750506000910152565b81810151838201526020016102c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610324815180928187528780880191016102c5565b0116010190565b90602061023d9281815201906102e8565b34610133576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d57610374610a5b565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116101fb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761044a610110565b6024359067ffffffffffffffff8211610133573660238301121561013357816004013590610477826103d9565b9161048560405193846101ba565b80835236602482860101116101335760208160009260246104ae97018387013784010152610d5f565b005b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435600052600260205261010961054c6040600020610200565b6040519182916020835260208301906102e8565b602080820190808352835180925260408301928160408460051b8301019501936000915b8483106105945750505050505090565b90919293949584806105d0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a516102e8565b9801930193019194939290610584565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576004803567ffffffffffffffff918282116101335736602383011215610133578181013592831161013357602490818301928236918660051b010111610133576106543415610ada565b61065d84610b57565b9360005b81811061067657604051806101098882610560565b600080610684838589610c49565b60409391610696855180938193610cae565b0390305af4906106a4610cbc565b918290156106d3575050906106ce916106bd8289610d4b565b526106c88188610d4b565b50610bbe565b610661565b868387926044825110610133578261072593856106f69401518301019101610cec565b92519283927f08c379a0000000000000000000000000000000000000000000000000000000008452830161032b565b0390fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335767ffffffffffffffff600435602480358381116101335736602382011215610133578060040135938411610133573682858301011161013357610799610a5b565b60009383855260206002815260408620906107be836107b88454610138565b84610f30565b8690601f841160011461085157509161083e9181867f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f499796958a92610844575b50508260011b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8460031b1c19161790555b6040519384930183610f84565b0390a280f35b86010135905085386107fe565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841661088484600052602060002090565b9289905b82821061090c5750509161083e9391857f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f4998979694106108d2575b5050600182811b019055610831565b867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19918701013516905538806108c3565b80600185968b8395978c0101358155019501930190610888565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761095d610110565b610965610a5b565b73ffffffffffffffffffffffffffffffffffffffff80911680156109d7576000918254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff600054163303610a7c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15610ae157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152fd5b67ffffffffffffffff81116101fb5760051b60200190565b90610b6182610b3f565b610b6e60405191826101ba565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610b9c8294610b3f565b019060005b828110610bad57505050565b806060602080938501015201610ba1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610beb5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015610ca95760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020018236038113610133579190565b610c1a565b908092918237016000815290565b3d15610ce7573d90610ccd826103d9565b91610cdb60405193846101ba565b82523d6000602084013e565b606090565b6020818303126101335780519067ffffffffffffffff8211610133570181601f82011215610133578051610d1f816103d9565b92610d2d60405194856101ba565b818452602082840101116101335761023d91602080850191016102c5565b8051821015610ca95760209160051b010190565b73ffffffffffffffffffffffffffffffffffffffff90610d7d610a5b565b1690816000526001602081815260406000209183519167ffffffffffffffff83116101fb57610db683610db08654610138565b86610f30565b80601f8411600114610e61575091610e31939181807f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd9795600092610e36575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91921b9260031b1c19161790556040519182918261032b565b0390a2565b86015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610df6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084939416610e9686600052602060002090565b926000905b828210610f19575050918391610e3196947f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd98969410610ee2575b5050811b0190556100fd565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880610ed6565b808785968294968c01518155019501930190610e9b565b90601f8111610f3e57505050565b600091825260208220906020601f850160051c83019410610f7a575b601f0160051c01915b828110610f6f57505050565b818155600101610f63565b9092508290610f5a565b90601f836040947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09360208652816020870152868601376000858286010152011601019056fea26469706673582212203c05d8358a45c791a110df40ff71f94d279750050c70155a559409bceaabc4ae64736f6c63430008120033", "deployedBytecode": "0x6080604052600436101561001257600080fd5b6000803560e01c90816350fbbd011461009a57508063715018a6146100955780638098b875146100905780638da5cb5b1461008b5780639fdd403a14610086578063ac9650d814610081578063e5e818ae1461007c5763f2fde38b1461007757600080fd5b610926565b610729565b6105e0565b610502565b6104b0565b610413565b61033c565b3461010d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d576100fd60406101099273ffffffffffffffffffffffffffffffffffffffff6100ef610110565b168152600160205220610200565b6040519182918261032b565b0390f35b80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361013357565b600080fd5b90600182811c92168015610181575b602083101461015257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610147565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101fb57604052565b61018b565b6040519081600082549261021384610138565b9081845260019485811690816000146102835750600114610240575b505061023d925003826101ba565b90565b9093915060005260209081600020936000915b81831061026b57505061023d9350820101388061022f565b85548784018501529485019486945091830191610253565b905061023d9550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101388061022f565b60005b8381106102d85750506000910152565b81810151838201526020016102c8565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610324815180928187528780880191016102c5565b0116010190565b90602061023d9281815201906102e8565b34610133576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010d57610374610a5b565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116101fb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761044a610110565b6024359067ffffffffffffffff8211610133573660238301121561013357816004013590610477826103d9565b9161048560405193846101ba565b80835236602482860101116101335760208160009260246104ae97018387013784010152610d5f565b005b346101335760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261013357600435600052600260205261010961054c6040600020610200565b6040519182916020835260208301906102e8565b602080820190808352835180925260408301928160408460051b8301019501936000915b8483106105945750505050505090565b90919293949584806105d0837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a516102e8565b9801930193019194939290610584565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610133576004803567ffffffffffffffff918282116101335736602383011215610133578181013592831161013357602490818301928236918660051b010111610133576106543415610ada565b61065d84610b57565b9360005b81811061067657604051806101098882610560565b600080610684838589610c49565b60409391610696855180938193610cae565b0390305af4906106a4610cbc565b918290156106d3575050906106ce916106bd8289610d4b565b526106c88188610d4b565b50610bbe565b610661565b868387926044825110610133578261072593856106f69401518301019101610cec565b92519283927f08c379a0000000000000000000000000000000000000000000000000000000008452830161032b565b0390fd5b346101335760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335767ffffffffffffffff600435602480358381116101335736602382011215610133578060040135938411610133573682858301011161013357610799610a5b565b60009383855260206002815260408620906107be836107b88454610138565b84610f30565b8690601f841160011461085157509161083e9181867f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f499796958a92610844575b50508260011b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8460031b1c19161790555b6040519384930183610f84565b0390a280f35b86010135905085386107fe565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841661088484600052602060002090565b9289905b82821061090c5750509161083e9391857f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f4998979694106108d2575b5050600182811b019055610831565b867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c19918701013516905538806108c3565b80600185968b8395978c0101358155019501930190610888565b346101335760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101335761095d610110565b610965610a5b565b73ffffffffffffffffffffffffffffffffffffffff80911680156109d7576000918254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff600054163303610a7c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15610ae157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152fd5b67ffffffffffffffff81116101fb5760051b60200190565b90610b6182610b3f565b610b6e60405191826101ba565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610b9c8294610b3f565b019060005b828110610bad57505050565b806060602080938501015201610ba1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610beb5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015610ca95760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561013357019081359167ffffffffffffffff8311610133576020018236038113610133579190565b610c1a565b908092918237016000815290565b3d15610ce7573d90610ccd826103d9565b91610cdb60405193846101ba565b82523d6000602084013e565b606090565b6020818303126101335780519067ffffffffffffffff8211610133570181601f82011215610133578051610d1f816103d9565b92610d2d60405194856101ba565b818452602082840101116101335761023d91602080850191016102c5565b8051821015610ca95760209160051b010190565b73ffffffffffffffffffffffffffffffffffffffff90610d7d610a5b565b1690816000526001602081815260406000209183519167ffffffffffffffff83116101fb57610db683610db08654610138565b86610f30565b80601f8411600114610e61575091610e31939181807f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd9795600092610e36575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91921b9260031b1c19161790556040519182918261032b565b0390a2565b86015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610df6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084939416610e9686600052602060002090565b926000905b828210610f19575050918391610e3196947f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd98969410610ee2575b5050811b0190556100fd565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880610ed6565b808785968294968c01518155019501930190610e9b565b90601f8111610f3e57505050565b600091825260208220906020601f850160051c83019410610f7a575b601f0160051c01915b828110610f6f57505050565b818155600101610f63565b9092508290610f5a565b90601f836040947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09360208652816020870152868601376000858286010152011601019056fea26469706673582212203c05d8358a45c791a110df40ff71f94d279750050c70155a559409bceaabc4ae64736f6c63430008120033", "devdoc": { diff --git a/deployments/goerli/AcrossMerkleDistributor.json b/deployments/goerli/AcrossMerkleDistributor.json index f2e062fa..1b6a0200 100644 --- a/deployments/goerli/AcrossMerkleDistributor.json +++ b/deployments/goerli/AcrossMerkleDistributor.json @@ -619,7 +619,7 @@ }, "args": [], "solcInputHash": "0c0f7cf4c33344752a752d4aad8f0613", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"ClaimFor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardsDeposited\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"CreatedWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"DeleteWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"WhitelistedClaimer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"WithdrawRewards\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claimFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim[]\",\"name\":\"claims\",\"type\":\"tuple[]\"}],\"name\":\"claimMulti\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"deleteWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"getRewardTokenForWindow\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"}],\"name\":\"isClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"merkleWindows\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"remainingAmount\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCreatedIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rewardsToDeposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"name\":\"setWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"whitelistClaimer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedClaimers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"rewardCurrency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Claim recipient must be equal to msg.sender.\",\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"}},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Caller must be in whitelistedClaimers struct set to \\\"true\\\".\",\"params\":{\"_claim\":\"leaf to claim.\"}},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"details\":\"All claim recipients must be equal to msg.sender.\",\"params\":{\"claims\":\"array of claims to claim.\"}},\"deleteWindow(uint256)\":{\"details\":\"Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\",\"params\":{\"windowIndex\":\"merkle root index to delete.\"}},\"getRewardTokenForWindow(uint256)\":{\"params\":{\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"address Reward token address\"}},\"isClaimed(uint256,uint256)\":{\"details\":\"This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`. The onus is on the Owner of this contract to submit only valid Merkle roots.\",\"params\":{\"accountIndex\":\"account index to check within window index.\",\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"True if claim has been executed already, False otherwise.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setWindow(uint256,address,bytes32,string)\":{\"params\":{\"ipfsHash\":\"hash of IPFS object, conveniently stored for clients\",\"merkleRoot\":\"merkle root describing allocation.\",\"rewardToken\":\"ERC20 reward token.\",\"rewardsToDeposit\":\"amount of rewards to deposit to seed this allocation.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"},\"returns\":{\"valid\":\"True if leaf exists.\"}},\"whitelistClaimer(address,bool)\":{\"details\":\"Callable only by owner.\",\"params\":{\"newContract\":\"Reset claimer contract to this address.\",\"whitelist\":\"True to whitelist claimer, False otherwise.\"}},\"withdrawRewards(address,uint256)\":{\"details\":\"Callable only by owner.\",\"params\":{\"amount\":\"amount of rewards to withdraw.\",\"rewardCurrency\":\"rewards to withdraw from contract.\"}}},\"title\":\"Extended MerkleDistributor contract.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Claim amount of reward tokens for account, as described by Claim input object.\"},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Executes merkle leaf claim on behaf of user. This can only be called by a trusted claimer address. This function is designed to be called atomically with other transactions that ultimately return the claimed amount to the rightful recipient. For example, AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\"},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"notice\":\"Batch claims to reduce gas versus individual submitting all claims. Method will fail if any individual claims within the batch would fail.\"},\"deleteWindow(uint256)\":{\"notice\":\"Delete merkle root at window index.\"},\"getRewardTokenForWindow(uint256)\":{\"notice\":\"Returns rewardToken set by admin for windowIndex.\"},\"isClaimed(uint256,uint256)\":{\"notice\":\"Returns True if the claim for `accountIndex` has already been completed for the Merkle root at `windowIndex`.\"},\"setWindow(uint256,address,bytes32,string)\":{\"notice\":\"Set merkle root for the next available window index and seed allocations.Callable only by owner of this contract. Caller must have approved this contract to transfer `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all claims within the `merkleRoot`.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given window index.\"},\"whitelistClaimer(address,bool)\":{\"notice\":\"Updates whitelisted claimer status.\"},\"withdrawRewards(address,uint256)\":{\"notice\":\"Emergency method that transfers rewards out of the contract if the contract was configured improperly.\"}},\"notice\":\"Adds additional constraints governing who can claim leaves from merkle windows.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":\"AcrossMerkleDistributor\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./MerkleDistributorInterface.sol\\\";\\n\\n/**\\n * Inspired by:\\n * - https://github.com/pie-dao/vested-token-migration-app\\n * - https://github.com/Uniswap/merkle-distributor\\n * - https://github.com/balancer-labs/erc20-redeemable\\n *\\n * @title MerkleDistributor contract.\\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\\n * multiple Merkle roots distributions with customized reward currencies.\\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\\n */\\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\\n using SafeERC20 for IERC20;\\n\\n // Windows are mapped to arbitrary indices.\\n mapping(uint256 => Window) public merkleWindows;\\n\\n // Index of next created Merkle root.\\n uint256 public nextCreatedIndex;\\n\\n // Track which accounts have claimed for each window index.\\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event Claimed(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n event CreatedWindow(\\n uint256 indexed windowIndex,\\n uint256 rewardsDeposited,\\n address indexed rewardToken,\\n address owner\\n );\\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\\n event DeleteWindow(uint256 indexed windowIndex, address owner);\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Set merkle root for the next available window index and seed allocations.\\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\\n * claims within the `merkleRoot`.\\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\\n * @param rewardToken ERC20 reward token.\\n * @param merkleRoot merkle root describing allocation.\\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\\n */\\n function setWindow(\\n uint256 rewardsToDeposit,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string calldata ipfsHash\\n ) external onlyOwner {\\n uint256 indexToSet = nextCreatedIndex;\\n nextCreatedIndex = indexToSet + 1;\\n\\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\\n }\\n\\n /**\\n * @notice Delete merkle root at window index.\\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\\n * @param windowIndex merkle root index to delete.\\n */\\n function deleteWindow(uint256 windowIndex) external onlyOwner {\\n delete merkleWindows[windowIndex];\\n emit DeleteWindow(windowIndex, msg.sender);\\n }\\n\\n /**\\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\\n * @dev Callable only by owner.\\n * @param rewardCurrency rewards to withdraw from contract.\\n * @param amount amount of rewards to withdraw.\\n */\\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\\n rewardCurrency.safeTransfer(msg.sender, amount);\\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public virtual override {\\n uint256 batchedAmount;\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n Claim memory _claim = claims[i];\\n _verifyAndMarkClaimed(_claim);\\n batchedAmount += _claim.amount;\\n\\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\\n uint256 nextI = i + 1;\\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\\n if (\\n nextI == claimCount ||\\n // This claim is last claim.\\n claims[nextI].account != _claim.account ||\\n // Next claim account is different than current one.\\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\\n // Next claim reward token is different than current one.\\n ) {\\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\\n batchedAmount = 0;\\n }\\n }\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public virtual override {\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\\n }\\n\\n /**\\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\\n * `windowIndex`.\\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\\n * @param windowIndex merkle root to check.\\n * @param accountIndex account index to check within window index.\\n * @return True if claim has been executed already, False otherwise.\\n */\\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Returns rewardToken set by admin for windowIndex.\\n * @param windowIndex merkle root to check.\\n * @return address Reward token address\\n */\\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\\n return address(merkleWindows[windowIndex].rewardToken);\\n }\\n\\n /**\\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\\n * window index.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n * @return valid True if leaf exists.\\n */\\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\\n }\\n\\n /****************************\\n * PRIVATE FUNCTIONS\\n ****************************/\\n\\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n claimedBitMap[windowIndex][claimedWordIndex] =\\n claimedBitMap[windowIndex][claimedWordIndex] |\\n (1 << claimedBitIndex);\\n }\\n\\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\\n function _setWindow(\\n uint256 windowIndex,\\n uint256 rewardsDeposited,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string memory ipfsHash\\n ) private {\\n Window storage window = merkleWindows[windowIndex];\\n window.merkleRoot = merkleRoot;\\n window.remainingAmount = rewardsDeposited;\\n window.rewardToken = IERC20(rewardToken);\\n window.ipfsHash = ipfsHash;\\n\\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\\n\\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\\n }\\n\\n // Verify claim is valid and mark it as completed in this contract.\\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\\n // Check claimed proof against merkle window at given index.\\n require(verifyClaim(_claim), \\\"Incorrect merkle proof\\\");\\n // Check the account has not yet claimed for this window.\\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \\\"Account has already claimed for this window\\\");\\n\\n // Proof is correct and claim has not occurred yet, mark claimed complete.\\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\\n emit Claimed(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x45ba14976c04b585ff82098ef0340ae062d9da7a3a2076b2535dbd194d254fc7\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\\n */\\ninterface MerkleDistributorInterface {\\n // A Window maps a Merkle root to a reward token address.\\n struct Window {\\n // Merkle root describing the distribution.\\n bytes32 merkleRoot;\\n // Remaining amount of deposited rewards that have not yet been claimed.\\n uint256 remainingAmount;\\n // Currency in which reward is processed.\\n IERC20 rewardToken;\\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\\n // data type for storing an IPFS hash is a multihash which is the concatenation of \\n // . We opted to store this in a string type to make it easier\\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\\n // go to https://cloudflare-ipfs.com/ipfs/.\\n string ipfsHash;\\n }\\n\\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\\n struct Claim {\\n uint256 windowIndex;\\n uint256 amount;\\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\\n address account;\\n bytes32[] merkleProof;\\n }\\n\\n function claim(Claim memory _claim) external;\\n\\n function claimMulti(Claim[] memory claims) external;\\n\\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\\n}\\n\",\"keccak256\":\"0x0d6527f44b268c3801d45bc1fc6021f22a80070a21d4066430a4d6566e3ff5e7\",\"license\":\"GPL-3.0-only\"},\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title Extended MerkleDistributor contract.\\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\\n */\\ncontract AcrossMerkleDistributor is MerkleDistributor {\\n using SafeERC20 for IERC20;\\n\\n // Addresses that can claim on user's behalf.\\n mapping(address => bool) public whitelistedClaimers;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\\n event ClaimFor(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Updates whitelisted claimer status.\\n * @dev Callable only by owner.\\n * @param newContract Reset claimer contract to this address.\\n * @param whitelist True to whitelist claimer, False otherwise.\\n */\\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\\n whitelistedClaimers[newContract] = whitelist;\\n emit WhitelistedClaimer(newContract, whitelist);\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev All claim recipients must be equal to msg.sender.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public override {\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n require(claims[i].account == msg.sender, \\\"invalid claimer\\\");\\n }\\n super.claimMulti(claims);\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev Claim recipient must be equal to msg.sender.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public override {\\n require(_claim.account == msg.sender, \\\"invalid claimer\\\");\\n super.claim(_claim);\\n }\\n\\n /**\\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\\n * claimer address. This function is designed to be called atomically with other transactions\\n * that ultimately return the claimed amount to the rightful recipient. For example,\\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\\n * @dev Caller must be in whitelistedClaimers struct set to \\\"true\\\".\\n * @param _claim leaf to claim.\\n */\\n\\n function claimFor(Claim memory _claim) public {\\n require(whitelistedClaimers[msg.sender], \\\"unwhitelisted claimer\\\");\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\\n emit ClaimFor(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x770e7f0986351870b1223a1214aaa3084b7cba9f438d7906c62c016ebd11b2c3\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"ClaimFor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardsDeposited\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"CreatedWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"DeleteWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"WhitelistedClaimer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"WithdrawRewards\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"claimFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim[]\",\"name\":\"claims\",\"type\":\"tuple[]\"}],\"name\":\"claimMulti\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"deleteWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"}],\"name\":\"getRewardTokenForWindow\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"}],\"name\":\"isClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"merkleWindows\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"remainingAmount\",\"type\":\"uint256\"},{\"internalType\":\"contract IERC20\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCreatedIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rewardsToDeposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"ipfsHash\",\"type\":\"string\"}],\"name\":\"setWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"windowIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"accountIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"internalType\":\"struct MerkleDistributorInterface.Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"whitelist\",\"type\":\"bool\"}],\"name\":\"whitelistClaimer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"whitelistedClaimers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"rewardCurrency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Claim recipient must be equal to msg.sender.\",\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"}},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"details\":\"Caller must be in whitelistedClaimers struct set to \\\"true\\\".\",\"params\":{\"_claim\":\"leaf to claim.\"}},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"details\":\"All claim recipients must be equal to msg.sender.\",\"params\":{\"claims\":\"array of claims to claim.\"}},\"deleteWindow(uint256)\":{\"details\":\"Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\",\"params\":{\"windowIndex\":\"merkle root index to delete.\"}},\"getRewardTokenForWindow(uint256)\":{\"params\":{\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"address Reward token address\"}},\"isClaimed(uint256,uint256)\":{\"details\":\"This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`. The onus is on the Owner of this contract to submit only valid Merkle roots.\",\"params\":{\"accountIndex\":\"account index to check within window index.\",\"windowIndex\":\"merkle root to check.\"},\"returns\":{\"_0\":\"True if claim has been executed already, False otherwise.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setWindow(uint256,address,bytes32,string)\":{\"params\":{\"ipfsHash\":\"hash of IPFS object, conveniently stored for clients\",\"merkleRoot\":\"merkle root describing allocation.\",\"rewardToken\":\"ERC20 reward token.\",\"rewardsToDeposit\":\"amount of rewards to deposit to seed this allocation.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"params\":{\"_claim\":\"claim object describing amount, accountIndex, account, window index, and merkle proof.\"},\"returns\":{\"valid\":\"True if leaf exists.\"}},\"whitelistClaimer(address,bool)\":{\"details\":\"Callable only by owner.\",\"params\":{\"newContract\":\"Reset claimer contract to this address.\",\"whitelist\":\"True to whitelist claimer, False otherwise.\"}},\"withdrawRewards(address,uint256)\":{\"details\":\"Callable only by owner.\",\"params\":{\"amount\":\"amount of rewards to withdraw.\",\"rewardCurrency\":\"rewards to withdraw from contract.\"}}},\"title\":\"Extended MerkleDistributor contract.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Claim amount of reward tokens for account, as described by Claim input object.\"},\"claimFor((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Executes merkle leaf claim on behaf of user. This can only be called by a trusted claimer address. This function is designed to be called atomically with other transactions that ultimately return the claimed amount to the rightful recipient. For example, AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\"},\"claimMulti((uint256,uint256,uint256,address,bytes32[])[])\":{\"notice\":\"Batch claims to reduce gas versus individual submitting all claims. Method will fail if any individual claims within the batch would fail.\"},\"deleteWindow(uint256)\":{\"notice\":\"Delete merkle root at window index.\"},\"getRewardTokenForWindow(uint256)\":{\"notice\":\"Returns rewardToken set by admin for windowIndex.\"},\"isClaimed(uint256,uint256)\":{\"notice\":\"Returns True if the claim for `accountIndex` has already been completed for the Merkle root at `windowIndex`.\"},\"setWindow(uint256,address,bytes32,string)\":{\"notice\":\"Set merkle root for the next available window index and seed allocations.Callable only by owner of this contract. Caller must have approved this contract to transfer `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all claims within the `merkleRoot`.\"},\"verifyClaim((uint256,uint256,uint256,address,bytes32[]))\":{\"notice\":\"Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given window index.\"},\"whitelistClaimer(address,bool)\":{\"notice\":\"Updates whitelisted claimer status.\"},\"withdrawRewards(address,uint256)\":{\"notice\":\"Emergency method that transfers rewards out of the contract if the contract was configured improperly.\"}},\"notice\":\"Adds additional constraints governing who can claim leaves from merkle windows.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":\"AcrossMerkleDistributor\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./MerkleDistributorInterface.sol\\\";\\n\\n/**\\n * Inspired by:\\n * - https://github.com/pie-dao/vested-token-migration-app\\n * - https://github.com/Uniswap/merkle-distributor\\n * - https://github.com/balancer-labs/erc20-redeemable\\n *\\n * @title MerkleDistributor contract.\\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\\n * multiple Merkle roots distributions with customized reward currencies.\\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\\n */\\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\\n using SafeERC20 for IERC20;\\n\\n // Windows are mapped to arbitrary indices.\\n mapping(uint256 => Window) public merkleWindows;\\n\\n // Index of next created Merkle root.\\n uint256 public nextCreatedIndex;\\n\\n // Track which accounts have claimed for each window index.\\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event Claimed(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n event CreatedWindow(\\n uint256 indexed windowIndex,\\n uint256 rewardsDeposited,\\n address indexed rewardToken,\\n address owner\\n );\\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\\n event DeleteWindow(uint256 indexed windowIndex, address owner);\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Set merkle root for the next available window index and seed allocations.\\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\\n * claims within the `merkleRoot`.\\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\\n * @param rewardToken ERC20 reward token.\\n * @param merkleRoot merkle root describing allocation.\\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\\n */\\n function setWindow(\\n uint256 rewardsToDeposit,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string calldata ipfsHash\\n ) external onlyOwner {\\n uint256 indexToSet = nextCreatedIndex;\\n nextCreatedIndex = indexToSet + 1;\\n\\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\\n }\\n\\n /**\\n * @notice Delete merkle root at window index.\\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\\n * @param windowIndex merkle root index to delete.\\n */\\n function deleteWindow(uint256 windowIndex) external onlyOwner {\\n delete merkleWindows[windowIndex];\\n emit DeleteWindow(windowIndex, msg.sender);\\n }\\n\\n /**\\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\\n * @dev Callable only by owner.\\n * @param rewardCurrency rewards to withdraw from contract.\\n * @param amount amount of rewards to withdraw.\\n */\\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\\n rewardCurrency.safeTransfer(msg.sender, amount);\\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public virtual override {\\n uint256 batchedAmount;\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n Claim memory _claim = claims[i];\\n _verifyAndMarkClaimed(_claim);\\n batchedAmount += _claim.amount;\\n\\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\\n uint256 nextI = i + 1;\\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\\n if (\\n nextI == claimCount ||\\n // This claim is last claim.\\n claims[nextI].account != _claim.account ||\\n // Next claim account is different than current one.\\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\\n // Next claim reward token is different than current one.\\n ) {\\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\\n batchedAmount = 0;\\n }\\n }\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public virtual override {\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\\n }\\n\\n /**\\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\\n * `windowIndex`.\\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\\n * @param windowIndex merkle root to check.\\n * @param accountIndex account index to check within window index.\\n * @return True if claim has been executed already, False otherwise.\\n */\\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Returns rewardToken set by admin for windowIndex.\\n * @param windowIndex merkle root to check.\\n * @return address Reward token address\\n */\\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\\n return address(merkleWindows[windowIndex].rewardToken);\\n }\\n\\n /**\\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\\n * window index.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n * @return valid True if leaf exists.\\n */\\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\\n }\\n\\n /****************************\\n * PRIVATE FUNCTIONS\\n ****************************/\\n\\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\\n uint256 claimedWordIndex = accountIndex / 256;\\n uint256 claimedBitIndex = accountIndex % 256;\\n claimedBitMap[windowIndex][claimedWordIndex] =\\n claimedBitMap[windowIndex][claimedWordIndex] |\\n (1 << claimedBitIndex);\\n }\\n\\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\\n function _setWindow(\\n uint256 windowIndex,\\n uint256 rewardsDeposited,\\n address rewardToken,\\n bytes32 merkleRoot,\\n string memory ipfsHash\\n ) private {\\n Window storage window = merkleWindows[windowIndex];\\n window.merkleRoot = merkleRoot;\\n window.remainingAmount = rewardsDeposited;\\n window.rewardToken = IERC20(rewardToken);\\n window.ipfsHash = ipfsHash;\\n\\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\\n\\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\\n }\\n\\n // Verify claim is valid and mark it as completed in this contract.\\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\\n // Check claimed proof against merkle window at given index.\\n require(verifyClaim(_claim), \\\"Incorrect merkle proof\\\");\\n // Check the account has not yet claimed for this window.\\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \\\"Account has already claimed for this window\\\");\\n\\n // Proof is correct and claim has not occurred yet, mark claimed complete.\\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\\n emit Claimed(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x45ba14976c04b585ff82098ef0340ae062d9da7a3a2076b2535dbd194d254fc7\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\\n */\\ninterface MerkleDistributorInterface {\\n // A Window maps a Merkle root to a reward token address.\\n struct Window {\\n // Merkle root describing the distribution.\\n bytes32 merkleRoot;\\n // Remaining amount of deposited rewards that have not yet been claimed.\\n uint256 remainingAmount;\\n // Currency in which reward is processed.\\n IERC20 rewardToken;\\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\\n // data type for storing an IPFS hash is a multihash which is the concatenation of \\n // . We opted to store this in a string type to make it easier\\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\\n // go to https://cloudflare-ipfs.com/ipfs/.\\n string ipfsHash;\\n }\\n\\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\\n struct Claim {\\n uint256 windowIndex;\\n uint256 amount;\\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\\n address account;\\n bytes32[] merkleProof;\\n }\\n\\n function claim(Claim memory _claim) external;\\n\\n function claimMulti(Claim[] memory claims) external;\\n\\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\\n}\\n\",\"keccak256\":\"0x0d6527f44b268c3801d45bc1fc6021f22a80070a21d4066430a4d6566e3ff5e7\",\"license\":\"GPL-3.0-only\"},\"contracts/merkle-distributor/AcrossMerkleDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title Extended MerkleDistributor contract.\\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\\n */\\ncontract AcrossMerkleDistributor is MerkleDistributor {\\n using SafeERC20 for IERC20;\\n\\n // Addresses that can claim on user's behalf.\\n mapping(address => bool) public whitelistedClaimers;\\n\\n /****************************************\\n * EVENTS\\n ****************************************/\\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\\n event ClaimFor(\\n address indexed caller,\\n uint256 windowIndex,\\n address indexed account,\\n uint256 accountIndex,\\n uint256 amount,\\n address indexed rewardToken\\n );\\n\\n /****************************\\n * ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Updates whitelisted claimer status.\\n * @dev Callable only by owner.\\n * @param newContract Reset claimer contract to this address.\\n * @param whitelist True to whitelist claimer, False otherwise.\\n */\\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\\n whitelistedClaimers[newContract] = whitelist;\\n emit WhitelistedClaimer(newContract, whitelist);\\n }\\n\\n /****************************\\n * NON-ADMIN FUNCTIONS\\n ****************************/\\n\\n /**\\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\\n * if any individual claims within the batch would fail.\\n * @dev All claim recipients must be equal to msg.sender.\\n * @param claims array of claims to claim.\\n */\\n function claimMulti(Claim[] memory claims) public override {\\n uint256 claimCount = claims.length;\\n for (uint256 i = 0; i < claimCount; i++) {\\n require(claims[i].account == msg.sender, \\\"invalid claimer\\\");\\n }\\n super.claimMulti(claims);\\n }\\n\\n /**\\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\\n * @dev Claim recipient must be equal to msg.sender.\\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\\n */\\n function claim(Claim memory _claim) public override {\\n require(_claim.account == msg.sender, \\\"invalid claimer\\\");\\n super.claim(_claim);\\n }\\n\\n /**\\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\\n * claimer address. This function is designed to be called atomically with other transactions\\n * that ultimately return the claimed amount to the rightful recipient. For example,\\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\\n * @dev Caller must be in whitelistedClaimers struct set to \\\"true\\\".\\n * @param _claim leaf to claim.\\n */\\n\\n function claimFor(Claim memory _claim) public {\\n require(whitelistedClaimers[msg.sender], \\\"unwhitelisted claimer\\\");\\n _verifyAndMarkClaimed(_claim);\\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\\n emit ClaimFor(\\n msg.sender,\\n _claim.windowIndex,\\n _claim.account,\\n _claim.accountIndex,\\n _claim.amount,\\n address(merkleWindows[_claim.windowIndex].rewardToken)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x770e7f0986351870b1223a1214aaa3084b7cba9f438d7906c62c016ebd11b2c3\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611c3c8061007e6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063d6ef7af011610066578063d6ef7af01461026b578063e2e441a31461027e578063f2fde38b14610295578063f364c90c146102a857600080fd5b80638da5cb5b146102145780639f5a967214610232578063a198496c14610245578063d45118681461025857600080fd5b8063743817a0116100d3578063743817a01461016d578063761b42971461018057806388f038a2146101de578063891b0d71146101f157600080fd5b80634f512151146101055780636be651791461012d57806370b53aee14610142578063715018a614610165575b600080fd5b610118610113366004611749565b6102bb565b60405190151581526020015b60405180910390f35b61014061013b36600461177e565b610377565b005b61011861015036600461182f565b60046020526000908152604090205460ff1681565b61014061045b565b61014061017b36600461185a565b61046f565b6101b961018e366004611893565b60009081526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101406101ec366004611749565b6104f6565b6102046101ff366004611893565b61063e565b6040516101249493929190611922565b60005473ffffffffffffffffffffffffffffffffffffffff166101b9565b610140610240366004611893565b610707565b610140610253366004611749565b61079a565b610140610266366004611967565b610829565b6101406102793660046119fd565b610890565b61028760025481565b604051908152602001610124565b6101406102a336600461182f565b61090a565b6101186102b6366004611a29565b6109be565b6000808260600151836020015184604001516040516020016103179392919060609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001683526014830191909152603482015260540190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120608086015186516000908152600190945291909220549192506103709183610a09565b9392505050565b805160005b8181101561044d573373ffffffffffffffffffffffffffffffffffffffff168382815181106103ad576103ad611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161461043b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d6572000000000000000000000000000000000060448201526064015b60405180910390fd5b8061044581611aa9565b91505061037c565b5061045782610a1f565b5050565b610463610bb3565b61046d6000610c34565b565b610477610bb3565b73ffffffffffffffffffffffffffffffffffffffff821660008181526004602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917fbaa2323ab54d3ecd5bd63d3c3cfc23d7ef896edcbc927b7b7867407f32a3ba2991a35050565b3360009081526004602052604090205460ff1661056f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f756e77686974656c697374656420636c61696d657200000000000000000000006044820152606401610432565b61057881610ca9565b6020808201518251600090815260019092526040909120600201546105b79173ffffffffffffffffffffffffffffffffffffffff909116903390610e7c565b805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917fcfb930b6b49765485460cb1c6853ec3437a78b18d8c9a25b9fed2eea3b6756a991015b60405180910390a450565b60016020819052600091825260409091208054918101546002820154600383018054929373ffffffffffffffffffffffffffffffffffffffff9092169261068490611ae1565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090611ae1565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905084565b61070f610bb3565b600081815260016020819052604082208281559081018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559061076060038301826114b7565b505060405133815281907f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d669060200160405180910390a250565b606081015173ffffffffffffffffffffffffffffffffffffffff16331461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d657200000000000000000000000000000000006044820152606401610432565b61082681610f55565b50565b610831610bb3565b60025461083f816001611b34565b6002819055506108888187878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fa092505050565b505050505050565b610898610bb3565b6108b973ffffffffffffffffffffffffffffffffffffffff83163383610e7c565b60405181815273ffffffffffffffffffffffffffffffffffffffff83169033907ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e9060200160405180910390a35050565b610912610bb3565b73ffffffffffffffffffffffffffffffffffffffff81166109b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610432565b61082681610c34565b6000806109cd61010084611b7b565b905060006109dd61010085611b8f565b60009586526003602090815260408088209488529390529190942054600190911b908116149392505050565b600082610a16858461108b565b14949350505050565b8051600090815b81811015610bad576000848281518110610a4257610a42611a4b565b60200260200101519050610a5581610ca9565b6020810151610a649085611b34565b93506000610a73836001611b34565b825160009081526001602052604090206002015490915073ffffffffffffffffffffffffffffffffffffffff1684821480610afb5750826060015173ffffffffffffffffffffffffffffffffffffffff16878381518110610ad657610ad6611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1614155b80610b6657508073ffffffffffffffffffffffffffffffffffffffff1660016000898581518110610b2e57610b2e611a4b565b6020908102919091018101515182528101919091526040016000206002015473ffffffffffffffffffffffffffffffffffffffff1614155b15610b97576060830151610b929073ffffffffffffffffffffffffffffffffffffffff83169088610e7c565b600095505b5050508080610ba590611aa9565b915050610a26565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610432565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cb2816102bb565b610d18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e636f7272656374206d65726b6c652070726f6f66000000000000000000006044820152606401610432565b610d2a816000015182604001516109be565b15610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060448201527f746869732077696e646f770000000000000000000000000000000000000000006064820152608401610432565b610dc9816000015182604001516110d8565b806020015160016000836000015181526020019081526020016000206001016000828254610df79190611ba3565b9091555050805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b49101610633565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610f509084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611121565b505050565b610f5e81610ca9565b60608101516020808301518351600090815260019092526040909120600201546108269273ffffffffffffffffffffffffffffffffffffffff90911691610e7c565b60008581526001602081815260409092208481559081018690556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055825190916110119160038401918501906114f1565b506040805186815233602082015273ffffffffffffffffffffffffffffffffffffffff86169188917f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad910160405180910390a360028101546108889073ffffffffffffffffffffffffffffffffffffffff1633308861122d565b600081815b84518110156110d0576110bc828683815181106110af576110af611a4b565b602002602001015161128b565b9150806110c881611aa9565b915050611090565b509392505050565b60006110e661010083611b7b565b905060006110f661010084611b8f565b6000948552600360209081526040808720948752939052919093208054600190921b90911790555050565b6000611183826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112b79092919063ffffffff16565b805190915015610f5057808060200190518101906111a19190611bba565b610f50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610432565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610bad9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610ece565b60008183106112a7576000828152602084905260409020610370565b5060009182526020526040902090565b60606112c684846000856112ce565b949350505050565b606082471015611360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610432565b73ffffffffffffffffffffffffffffffffffffffff85163b6113de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610432565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516114079190611bd7565b60006040518083038185875af1925050503d8060008114611444576040519150601f19603f3d011682016040523d82523d6000602084013e611449565b606091505b5091509150611459828286611464565b979650505050505050565b60608315611473575081610370565b8251156114835782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104329190611bf3565b5080546114c390611ae1565b6000825580601f106114d3575050565b601f0160209004906000526020600020908101906108269190611575565b8280546114fd90611ae1565b90600052602060002090601f01602090048101928261151f5760008555611565565b82601f1061153857805160ff1916838001178555611565565b82800160010185558215611565579182015b8281111561156557825182559160200191906001019061154a565b50611571929150611575565b5090565b5b808211156115715760008155600101611576565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115dc576115dc61158a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156116295761162961158a565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461082657600080fd5b600067ffffffffffffffff82111561166d5761166d61158a565b5060051b60200190565b600060a0828403121561168957600080fd5b6116916115b9565b905081358152602080830135818301526040830135604083015260608301356116b981611631565b6060830152608083013567ffffffffffffffff8111156116d857600080fd5b8301601f810185136116e957600080fd5b80356116fc6116f782611653565b6115e2565b81815260059190911b8201830190838101908783111561171b57600080fd5b928401925b8284101561173957833582529284019290840190611720565b6080860152509295945050505050565b60006020828403121561175b57600080fd5b813567ffffffffffffffff81111561177257600080fd5b6112c684828501611677565b6000602080838503121561179157600080fd5b823567ffffffffffffffff808211156117a957600080fd5b818501915085601f8301126117bd57600080fd5b81356117cb6116f782611653565b81815260059190911b830184019084810190888311156117ea57600080fd5b8585015b83811015611822578035858111156118065760008081fd5b6118148b89838a0101611677565b8452509186019186016117ee565b5098975050505050505050565b60006020828403121561184157600080fd5b813561037081611631565b801515811461082657600080fd5b6000806040838503121561186d57600080fd5b823561187881611631565b915060208301356118888161184c565b809150509250929050565b6000602082840312156118a557600080fd5b5035919050565b60005b838110156118c75781810151838201526020016118af565b83811115610bad5750506000910152565b600081518084526118f08160208601602086016118ac565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b84815283602082015273ffffffffffffffffffffffffffffffffffffffff8316604082015260806060820152600061195d60808301846118d8565b9695505050505050565b60008060008060006080868803121561197f57600080fd5b85359450602086013561199181611631565b935060408601359250606086013567ffffffffffffffff808211156119b557600080fd5b818801915088601f8301126119c957600080fd5b8135818111156119d857600080fd5b8960208285010111156119ea57600080fd5b9699959850939650602001949392505050565b60008060408385031215611a1057600080fd5b8235611a1b81611631565b946020939093013593505050565b60008060408385031215611a3c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ada57611ada611a7a565b5060010190565b600181811c90821680611af557607f821691505b602082108103611b2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008219821115611b4757611b47611a7a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611b8a57611b8a611b4c565b500490565b600082611b9e57611b9e611b4c565b500690565b600082821015611bb557611bb5611a7a565b500390565b600060208284031215611bcc57600080fd5b81516103708161184c565b60008251611be98184602087016118ac565b9190910192915050565b60208152600061037060208301846118d856fea26469706673582212204e7d4cbb315ebe595a6cc88f23a8e65a5517a72a4d9d103a40e984d8af7af15664736f6c634300080d0033", "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063d6ef7af011610066578063d6ef7af01461026b578063e2e441a31461027e578063f2fde38b14610295578063f364c90c146102a857600080fd5b80638da5cb5b146102145780639f5a967214610232578063a198496c14610245578063d45118681461025857600080fd5b8063743817a0116100d3578063743817a01461016d578063761b42971461018057806388f038a2146101de578063891b0d71146101f157600080fd5b80634f512151146101055780636be651791461012d57806370b53aee14610142578063715018a614610165575b600080fd5b610118610113366004611749565b6102bb565b60405190151581526020015b60405180910390f35b61014061013b36600461177e565b610377565b005b61011861015036600461182f565b60046020526000908152604090205460ff1681565b61014061045b565b61014061017b36600461185a565b61046f565b6101b961018e366004611893565b60009081526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6101406101ec366004611749565b6104f6565b6102046101ff366004611893565b61063e565b6040516101249493929190611922565b60005473ffffffffffffffffffffffffffffffffffffffff166101b9565b610140610240366004611893565b610707565b610140610253366004611749565b61079a565b610140610266366004611967565b610829565b6101406102793660046119fd565b610890565b61028760025481565b604051908152602001610124565b6101406102a336600461182f565b61090a565b6101186102b6366004611a29565b6109be565b6000808260600151836020015184604001516040516020016103179392919060609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001683526014830191909152603482015260540190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120608086015186516000908152600190945291909220549192506103709183610a09565b9392505050565b805160005b8181101561044d573373ffffffffffffffffffffffffffffffffffffffff168382815181106103ad576103ad611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161461043b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d6572000000000000000000000000000000000060448201526064015b60405180910390fd5b8061044581611aa9565b91505061037c565b5061045782610a1f565b5050565b610463610bb3565b61046d6000610c34565b565b610477610bb3565b73ffffffffffffffffffffffffffffffffffffffff821660008181526004602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917fbaa2323ab54d3ecd5bd63d3c3cfc23d7ef896edcbc927b7b7867407f32a3ba2991a35050565b3360009081526004602052604090205460ff1661056f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f756e77686974656c697374656420636c61696d657200000000000000000000006044820152606401610432565b61057881610ca9565b6020808201518251600090815260019092526040909120600201546105b79173ffffffffffffffffffffffffffffffffffffffff909116903390610e7c565b805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917fcfb930b6b49765485460cb1c6853ec3437a78b18d8c9a25b9fed2eea3b6756a991015b60405180910390a450565b60016020819052600091825260409091208054918101546002820154600383018054929373ffffffffffffffffffffffffffffffffffffffff9092169261068490611ae1565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090611ae1565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050505050905084565b61070f610bb3565b600081815260016020819052604082208281559081018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559061076060038301826114b7565b505060405133815281907f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d669060200160405180910390a250565b606081015173ffffffffffffffffffffffffffffffffffffffff16331461081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420636c61696d657200000000000000000000000000000000006044820152606401610432565b61082681610f55565b50565b610831610bb3565b60025461083f816001611b34565b6002819055506108888187878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fa092505050565b505050505050565b610898610bb3565b6108b973ffffffffffffffffffffffffffffffffffffffff83163383610e7c565b60405181815273ffffffffffffffffffffffffffffffffffffffff83169033907ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e9060200160405180910390a35050565b610912610bb3565b73ffffffffffffffffffffffffffffffffffffffff81166109b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610432565b61082681610c34565b6000806109cd61010084611b7b565b905060006109dd61010085611b8f565b60009586526003602090815260408088209488529390529190942054600190911b908116149392505050565b600082610a16858461108b565b14949350505050565b8051600090815b81811015610bad576000848281518110610a4257610a42611a4b565b60200260200101519050610a5581610ca9565b6020810151610a649085611b34565b93506000610a73836001611b34565b825160009081526001602052604090206002015490915073ffffffffffffffffffffffffffffffffffffffff1684821480610afb5750826060015173ffffffffffffffffffffffffffffffffffffffff16878381518110610ad657610ad6611a4b565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1614155b80610b6657508073ffffffffffffffffffffffffffffffffffffffff1660016000898581518110610b2e57610b2e611a4b565b6020908102919091018101515182528101919091526040016000206002015473ffffffffffffffffffffffffffffffffffffffff1614155b15610b97576060830151610b929073ffffffffffffffffffffffffffffffffffffffff83169088610e7c565b600095505b5050508080610ba590611aa9565b915050610a26565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610432565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cb2816102bb565b610d18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e636f7272656374206d65726b6c652070726f6f66000000000000000000006044820152606401610432565b610d2a816000015182604001516109be565b15610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060448201527f746869732077696e646f770000000000000000000000000000000000000000006064820152608401610432565b610dc9816000015182604001516110d8565b806020015160016000836000015181526020019081526020016000206001016000828254610df79190611ba3565b9091555050805160009081526001602090815260409182902060020154606080850151855185870151858801518751928352958201529485019390935273ffffffffffffffffffffffffffffffffffffffff91821693919092169133917f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b49101610633565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610f509084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611121565b505050565b610f5e81610ca9565b60608101516020808301518351600090815260019092526040909120600201546108269273ffffffffffffffffffffffffffffffffffffffff90911691610e7c565b60008581526001602081815260409092208481559081018690556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716179055825190916110119160038401918501906114f1565b506040805186815233602082015273ffffffffffffffffffffffffffffffffffffffff86169188917f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad910160405180910390a360028101546108889073ffffffffffffffffffffffffffffffffffffffff1633308861122d565b600081815b84518110156110d0576110bc828683815181106110af576110af611a4b565b602002602001015161128b565b9150806110c881611aa9565b915050611090565b509392505050565b60006110e661010083611b7b565b905060006110f661010084611b8f565b6000948552600360209081526040808720948752939052919093208054600190921b90911790555050565b6000611183826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112b79092919063ffffffff16565b805190915015610f5057808060200190518101906111a19190611bba565b610f50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610432565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610bad9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610ece565b60008183106112a7576000828152602084905260409020610370565b5060009182526020526040902090565b60606112c684846000856112ce565b949350505050565b606082471015611360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610432565b73ffffffffffffffffffffffffffffffffffffffff85163b6113de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610432565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516114079190611bd7565b60006040518083038185875af1925050503d8060008114611444576040519150601f19603f3d011682016040523d82523d6000602084013e611449565b606091505b5091509150611459828286611464565b979650505050505050565b60608315611473575081610370565b8251156114835782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104329190611bf3565b5080546114c390611ae1565b6000825580601f106114d3575050565b601f0160209004906000526020600020908101906108269190611575565b8280546114fd90611ae1565b90600052602060002090601f01602090048101928261151f5760008555611565565b82601f1061153857805160ff1916838001178555611565565b82800160010185558215611565579182015b8281111561156557825182559160200191906001019061154a565b50611571929150611575565b5090565b5b808211156115715760008155600101611576565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115dc576115dc61158a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156116295761162961158a565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461082657600080fd5b600067ffffffffffffffff82111561166d5761166d61158a565b5060051b60200190565b600060a0828403121561168957600080fd5b6116916115b9565b905081358152602080830135818301526040830135604083015260608301356116b981611631565b6060830152608083013567ffffffffffffffff8111156116d857600080fd5b8301601f810185136116e957600080fd5b80356116fc6116f782611653565b6115e2565b81815260059190911b8201830190838101908783111561171b57600080fd5b928401925b8284101561173957833582529284019290840190611720565b6080860152509295945050505050565b60006020828403121561175b57600080fd5b813567ffffffffffffffff81111561177257600080fd5b6112c684828501611677565b6000602080838503121561179157600080fd5b823567ffffffffffffffff808211156117a957600080fd5b818501915085601f8301126117bd57600080fd5b81356117cb6116f782611653565b81815260059190911b830184019084810190888311156117ea57600080fd5b8585015b83811015611822578035858111156118065760008081fd5b6118148b89838a0101611677565b8452509186019186016117ee565b5098975050505050505050565b60006020828403121561184157600080fd5b813561037081611631565b801515811461082657600080fd5b6000806040838503121561186d57600080fd5b823561187881611631565b915060208301356118888161184c565b809150509250929050565b6000602082840312156118a557600080fd5b5035919050565b60005b838110156118c75781810151838201526020016118af565b83811115610bad5750506000910152565b600081518084526118f08160208601602086016118ac565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b84815283602082015273ffffffffffffffffffffffffffffffffffffffff8316604082015260806060820152600061195d60808301846118d8565b9695505050505050565b60008060008060006080868803121561197f57600080fd5b85359450602086013561199181611631565b935060408601359250606086013567ffffffffffffffff808211156119b557600080fd5b818801915088601f8301126119c957600080fd5b8135818111156119d857600080fd5b8960208285010111156119ea57600080fd5b9699959850939650602001949392505050565b60008060408385031215611a1057600080fd5b8235611a1b81611631565b946020939093013593505050565b60008060408385031215611a3c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ada57611ada611a7a565b5060010190565b600181811c90821680611af557607f821691505b602082108103611b2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008219821115611b4757611b47611a7a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611b8a57611b8a611b4c565b500490565b600082611b9e57611b9e611b4c565b500690565b600082821015611bb557611bb5611a7a565b500390565b600060208284031215611bcc57600080fd5b81516103708161184c565b60008251611be98184602087016118ac565b9190910192915050565b60208152600061037060208301846118d856fea26469706673582212204e7d4cbb315ebe595a6cc88f23a8e65a5517a72a4d9d103a40e984d8af7af15664736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Arbitrum_Adapter.json b/deployments/goerli/Arbitrum_Adapter.json index 8db11bd4..1d7ddc15 100644 --- a/deployments/goerli/Arbitrum_Adapter.json +++ b/deployments/goerli/Arbitrum_Adapter.json @@ -224,7 +224,7 @@ "args": ["0x6BEbC4925716945D46F0Ec336D5C2564F419682C", "0x4c7708168395aEa569453Fc36862D2ffcDaC588c"], "numDeployments": 1, "solcInputHash": "2703c51b0457010edb5371429c04306b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2 and lost.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x26bf6695b4dc412fbacc090aae47284bfc6eb4cfc357dea4843fa74ccb96885d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2 and lost.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x26bf6695b4dc412fbacc090aae47284bfc6eb4cfc357dea4843fa74ccb96885d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052662386f26fc1000060805264012a05f20060a052621e848060c05234801561002c57600080fd5b5060405161128438038061128483398101604081905261004b91610080565b6001600160a01b039182166101005216610120523360e0526100ba565b6001600160a01b038116811461007d57600080fd5b50565b6000806040838503121561009357600080fd5b825161009e81610068565b60208401519092506100af81610068565b809150509250929050565b60805160a05160c05160e051610100516101205161111a61016a6000396000818160d501528181610333015261047001526000818161014301526105cd0152600081816101ab0152818161062e015261064f0152600081816101df01528181610269015281816104a501526106700152600081816101770152818161028b015281816104c70152610691015260008181610228015281816102b5015281816103c5015261060d015261111a6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212203e211fa11542a3146dbf1d5afde804b46ca1cc0ca35ecbd1eccc4f553457584d64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212203e211fa11542a3146dbf1d5afde804b46ca1cc0ca35ecbd1eccc4f553457584d64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Ethereum_Adapter.json b/deployments/goerli/Ethereum_Adapter.json index 9cbf6131..ceae3dc9 100644 --- a/deployments/goerli/Ethereum_Adapter.json +++ b/deployments/goerli/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "6f2837d4a3b71ee9ce7179486eec7c62", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n\\n bool success;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xcfef0f4e9715e55426bcb08f18a04d437358f381b456a2af7262ead48c6987cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n\\n bool success;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xcfef0f4e9715e55426bcb08f18a04d437358f381b456a2af7262ead48c6987cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220e95c79b0243d04b77fff68509adf0775fd47ea5ad3499e9e6141c4fdb0b5d6cc64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220e95c79b0243d04b77fff68509adf0775fd47ea5ad3499e9e6141c4fdb0b5d6cc64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/Ethereum_SpokePool.json b/deployments/goerli/Ethereum_SpokePool.json index 18adc445..222fb8ec 100644 --- a/deployments/goerli/Ethereum_SpokePool.json +++ b/deployments/goerli/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "6f2837d4a3b71ee9ce7179486eec7c62", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x84ac2d2f343df1e683da7a12bbcf70db542a7a7a0cea90a5d70fcb5e5d035481\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x84ac2d2f343df1e683da7a12bbcf70db542a7a7a0cea90a5d70fcb5e5d035481\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Tree proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n *\\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\\n * hashing, or use a hash function other than keccak256 for hashing leaves.\\n * This is because the concatenation of a sorted pair of internal nodes in\\n * the merkle tree could be reinterpreted as a leaf value.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {verify}\\n *\\n * _Available since v4.7._\\n */\\n function verifyCalldata(\\n bytes32[] calldata proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProofCalldata(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Calldata version of {processProof}\\n *\\n * _Available since v4.7._\\n */\\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n computedHash = _hashPair(computedHash, proof[i]);\\n }\\n return computedHash;\\n }\\n\\n /**\\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerify(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProof(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Calldata version of {multiProofVerify}\\n *\\n * _Available since v4.7._\\n */\\n function multiProofVerifyCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32 root,\\n bytes32[] memory leaves\\n ) internal pure returns (bool) {\\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\\n }\\n\\n /**\\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\\n * consuming from one or the other at each step according to the instructions given by\\n * `proofFlags`.\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProof(\\n bytes32[] memory proof,\\n bool[] memory proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n /**\\n * @dev Calldata version of {processMultiProof}\\n *\\n * _Available since v4.7._\\n */\\n function processMultiProofCalldata(\\n bytes32[] calldata proof,\\n bool[] calldata proofFlags,\\n bytes32[] memory leaves\\n ) internal pure returns (bytes32 merkleRoot) {\\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\\n // the merkle tree.\\n uint256 leavesLen = leaves.length;\\n uint256 totalHashes = proofFlags.length;\\n\\n // Check proof validity.\\n require(leavesLen + proof.length - 1 == totalHashes, \\\"MerkleProof: invalid multiproof\\\");\\n\\n // The xxxPos values are \\\"pointers\\\" to the next value to consume in each array. All accesses are done using\\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \\\"pop\\\".\\n bytes32[] memory hashes = new bytes32[](totalHashes);\\n uint256 leafPos = 0;\\n uint256 hashPos = 0;\\n uint256 proofPos = 0;\\n // At each step, we compute the next hash using two values:\\n // - a value from the \\\"main queue\\\". If not all leaves have been consumed, we get the next leaf, otherwise we\\n // get the next hash.\\n // - depending on the flag, either another value for the \\\"main queue\\\" (merging branches) or an element from the\\n // `proof` array.\\n for (uint256 i = 0; i < totalHashes; i++) {\\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\\n hashes[i] = _hashPair(a, b);\\n }\\n\\n if (totalHashes > 0) {\\n return hashes[totalHashes - 1];\\n } else if (leavesLen > 0) {\\n return leaves[0];\\n } else {\\n return proof[0];\\n }\\n }\\n\\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x596ed72a251d391b814a4aa19d7acb02ebdcc92ba27d3fff74a6f0c158b12ab7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./MerkleLib.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./SpokePoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\n\\n/**\\n * @title SpokePool\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\n */\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\n using SafeERC20 for IERC20;\\n using Address for address;\\n\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\n // then this address should be set to the same owner as the HubPool and the whole system.\\n address public crossDomainAdmin;\\n\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\n // refunds and slow relays.\\n address public hubPool;\\n\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\n WETH9 public immutable wrappedNativeToken;\\n\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\n uint32 public depositQuoteTimeBuffer = 600;\\n\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\n uint32 public numberOfDeposits;\\n\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\n RootBundle[] public rootBundles;\\n\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\n\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\n // relay, the fees, and the agents are all parameters included in the hash key.\\n mapping(bytes32 => uint256) public relayFills;\\n\\n /****************************************\\n * EVENTS *\\n ****************************************/\\n event SetXDomainAdmin(address indexed newAdmin);\\n event SetHubPool(address indexed newHubPool);\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\n event FundsDeposited(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n address indexed originToken,\\n address recipient,\\n address indexed depositor\\n );\\n event RequestedSpeedUpDeposit(\\n uint64 newRelayerFeePct,\\n uint32 indexed depositId,\\n address indexed depositor,\\n bytes depositorSignature\\n );\\n event FilledRelay(\\n uint256 amount,\\n uint256 totalFilledAmount,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint64 appliedRelayerFeePct,\\n uint64 realizedLpFeePct,\\n uint32 depositId,\\n address destinationToken,\\n address indexed relayer,\\n address indexed depositor,\\n address recipient,\\n bool isSlowRelay\\n );\\n event RelayedRootBundle(\\n uint32 indexed rootBundleId,\\n bytes32 indexed relayerRefundRoot,\\n bytes32 indexed slowRelayRoot\\n );\\n event ExecutedRelayerRefundRoot(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint256[] refundAmounts,\\n uint32 indexed rootBundleId,\\n uint32 indexed leafId,\\n address l2TokenAddress,\\n address[] refundAddresses,\\n address caller\\n );\\n event TokensBridged(\\n uint256 amountToReturn,\\n uint256 indexed chainId,\\n uint32 indexed leafId,\\n address indexed l2TokenAddress,\\n address caller\\n );\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\n\\n /**\\n * @notice Construct the base SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address _wrappedNativeTokenAddress,\\n address timerAddress\\n ) Testable(timerAddress) {\\n _setCrossDomainAdmin(_crossDomainAdmin);\\n _setHubPool(_hubPool);\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\n }\\n\\n /****************************************\\n * MODIFIERS *\\n ****************************************/\\n\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\n // appropriately.\\n modifier onlyAdmin() {\\n _requireAdminSender();\\n _;\\n }\\n\\n /**************************************\\n * ADMIN FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Change cross domain admin address. Callable by admin only.\\n * @param newCrossDomainAdmin New cross domain admin.\\n */\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n /**\\n * @notice Change L1 hub pool address. Callable by admin only.\\n * @param newHubPool New hub pool.\\n */\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\n _setHubPool(newHubPool);\\n }\\n\\n /**\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\n * @param originToken Token that depositor can deposit to this contract.\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\n * @param enabled True to enable deposits, False otherwise.\\n */\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enabled\\n ) public override onlyAdmin nonReentrant {\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\n }\\n\\n /**\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\n */\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\n }\\n\\n /**\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\n * executeRelayerRefundLeaf().\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\n * executeSlowRelayLeaf().\\n */\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\n uint32 rootBundleId = uint32(rootBundles.length);\\n RootBundle storage rootBundle = rootBundles.push();\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\n rootBundle.slowRelayRoot = slowRelayRoot;\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\n }\\n\\n /**\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\n * SpokePool.\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\n */\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\n delete rootBundles[rootBundleId];\\n emit EmergencyDeleteRootBundle(rootBundleId);\\n }\\n\\n /**************************************\\n * DEPOSITOR FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n * token mapping is stored on the L1 HubPool.\\n * @notice The caller must first approve this contract to spend amount of originToken.\\n * @notice The originToken => destinationChainId must be enabled.\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n */\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) public payable override nonReentrant {\\n // Check that deposit route is enabled.\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\n\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\n // buffer of this contract's block time to allow for this variance.\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\n require(\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\n \\\"invalid quote time\\\"\\n );\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\n wrappedNativeToken.deposit{ value: msg.value }();\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\n\\n _emitDeposit(\\n amount,\\n chainId(),\\n destinationChainId,\\n relayerFeePct,\\n numberOfDeposits,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n msg.sender\\n );\\n\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\n // @dev: Use pre-increment to save gas:\\n // i++ --> Load, Store, Add, Store\\n // ++i --> Load, Add, Store\\n ++numberOfDeposits;\\n }\\n\\n /**\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\n * update fee message.\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\n * did in fact submit a relay.\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\n * @param depositId Deposit to update fee for that originated in this contract.\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\n */\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\n\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\n\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\n // from the following event to submit a fill with an updated fee %.\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\n }\\n\\n /**************************************\\n * RELAYER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\n * then relayer will not receive any refund.\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\n * as described in a UMIP linked to the HubPool's identifier.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n */\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) public nonReentrant {\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\n }\\n\\n /**\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\n * send recipient the full relay amount.\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\n * passed.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\n */\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) public override nonReentrant {\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\n\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId,\\n originChainId: originChainId,\\n destinationChainId: chainId()\\n });\\n bytes32 relayHash = _getRelayHash(relayData);\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\n\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\n * relay to the recipient, less fees.\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\n * the caller from executing a slow relay intended for another chain on this chain.\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\n * @param recipient Specified recipient on this chain.\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\n * and this chain ID via a mapping on the HubPool.\\n * @param amount Full size of the deposit.\\n * @param originChainId Chain of SpokePool where deposit originated.\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\n * quote time.\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\n * @param depositId Unique deposit ID on origin spoke pool.\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n amount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\n * sent to the recipient plus a relayer fee.\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public virtual override nonReentrant {\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * VIEW FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Returns chain ID for this network.\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\n */\\n function chainId() public view virtual override returns (uint256) {\\n return block.chainid;\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\n // transfers.\\n function _executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) internal {\\n // Check integrity of leaf structure:\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\n\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\n\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\n\\n // Verify the leafId in the leaf has not yet been claimed.\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\n\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\n\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\n for (uint256 i = 0; i < length; ) {\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\n if (amount > 0)\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\n\\n // OK because we assume refund array length won't be > types(uint256).max.\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\n // not make it to this stage.\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\n // chain-specific bridging method.\\n if (relayerRefundLeaf.amountToReturn > 0) {\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\n\\n emit TokensBridged(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n msg.sender\\n );\\n }\\n\\n emit ExecutedRelayerRefundRoot(\\n relayerRefundLeaf.amountToReturn,\\n relayerRefundLeaf.chainId,\\n relayerRefundLeaf.refundAmounts,\\n rootBundleId,\\n relayerRefundLeaf.leafId,\\n relayerRefundLeaf.l2TokenAddress,\\n relayerRefundLeaf.refundAddresses,\\n msg.sender\\n );\\n }\\n\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\n function _executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) internal {\\n RelayData memory relayData = RelayData({\\n depositor: depositor,\\n recipient: recipient,\\n destinationToken: destinationToken,\\n amount: amount,\\n originChainId: originChainId,\\n destinationChainId: destinationChainId,\\n realizedLpFeePct: realizedLpFeePct,\\n relayerFeePct: relayerFeePct,\\n depositId: depositId\\n });\\n\\n require(\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\n \\\"Invalid proof\\\"\\n );\\n\\n bytes32 relayHash = _getRelayHash(relayData);\\n\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\n\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\n }\\n\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\n crossDomainAdmin = newCrossDomainAdmin;\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\n }\\n\\n function _setHubPool(address newHubPool) internal {\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\n hubPool = newHubPool;\\n emit SetHubPool(newHubPool);\\n }\\n\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\n\\n function _verifyUpdateRelayerFeeMessage(\\n address depositor,\\n uint256 originChainId,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) internal view {\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\n // in case this contract is upgraded.\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\n bytes32 expectedDepositorMessageHash = keccak256(\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\n );\\n\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\n // above keccak156 hash), then this will revert.\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\n\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\n }\\n\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\n function _verifyDepositorUpdateFeeMessage(\\n address depositor,\\n bytes32 ethSignedMessageHash,\\n bytes memory depositorSignature\\n ) internal view virtual {\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\n // chain does not have a parallel on this destination chain.\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\n }\\n\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (1e18 * amount) / (1e18 - feesPct);\\n }\\n\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\n return (amount * (1e18 - feesPct)) / 1e18;\\n }\\n\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\n return keccak256(abi.encode(relayData));\\n }\\n\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\n if (address(to).isContract()) {\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\n } else {\\n wrappedNativeToken.withdraw(amount);\\n to.transfer(amount);\\n }\\n }\\n\\n /**\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\n * and send to the recipient.\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\n */\\n function _fillRelay(\\n bytes32 relayHash,\\n RelayData memory relayData,\\n uint256 maxTokensToSend,\\n uint64 updatableRelayerFeePct,\\n bool useContractFunds\\n ) internal returns (uint256 fillAmountPreFees) {\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\n // computing the amount pre fees runs into divide-by-0 issues.\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\n\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\n\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\n if (maxTokensToSend == 0) return 0;\\n\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\n fillAmountPreFees = _computeAmountPreFees(\\n maxTokensToSend,\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\n );\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\n // we'll pull exactly enough tokens to complete the relay.\\n uint256 amountToSend = maxTokensToSend;\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\n if (amountRemainingInRelay < fillAmountPreFees) {\\n fillAmountPreFees = amountRemainingInRelay;\\n\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\n // this is a slow relay.\\n amountToSend = _computeAmountPostFees(\\n fillAmountPreFees,\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\n );\\n }\\n\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\n relayFills[relayHash] += fillAmountPreFees;\\n\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\n // need to unwrap it to native token before sending to the user.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\n // Else, this is a normal ERC20 token. Send to recipient.\\n } else {\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\n if (!useContractFunds)\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\n }\\n }\\n\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\n function _emitFillRelay(\\n bytes32 relayHash,\\n uint256 fillAmount,\\n uint256 repaymentChainId,\\n uint64 appliedRelayerFeePct,\\n RelayData memory relayData,\\n bool isSlowRelay\\n ) internal {\\n emit FilledRelay(\\n relayData.amount,\\n relayFills[relayHash],\\n fillAmount,\\n repaymentChainId,\\n relayData.originChainId,\\n relayData.destinationChainId,\\n relayData.relayerFeePct,\\n appliedRelayerFeePct,\\n relayData.realizedLpFeePct,\\n relayData.depositId,\\n relayData.destinationToken,\\n msg.sender,\\n relayData.depositor,\\n relayData.recipient,\\n isSlowRelay\\n );\\n }\\n\\n function _emitDeposit(\\n uint256 amount,\\n uint256 originChainId,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 quoteTimestamp,\\n address originToken,\\n address recipient,\\n address depositor\\n ) internal {\\n emit FundsDeposited(\\n amount,\\n originChainId,\\n destinationChainId,\\n relayerFeePct,\\n depositId,\\n quoteTimestamp,\\n originToken,\\n recipient,\\n depositor\\n );\\n }\\n\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\n // L1, this would just be the same admin of the HubPool.\\n function _requireAdminSender() internal virtual;\\n\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0x1113beb211ae3d34d987998059213ffb6cece4e4fcb0a032189fd5063da339b6\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xe7aa7638e79a7e89177536f8fabd458a4e9a87a2005f52c12d0c726bac5f0b58\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004589380380620045898339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b6080516142a0620002e9600039600081816101d901528181610ce601528181610daf0152818161226301528181612ae90152612b3f01526142a06000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461358b565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613687565b6106b0565b3480156102a057600080fd5b506102456102af3660046136a2565b61073d565b3480156102c057600080fd5b506102456102cf3660046136c9565b6107e6565b3480156102e057600080fd5b506102456102ef366004613709565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461373c565b610ab1565b34801561033657600080fd5b506102456103453660046137a2565b610f28565b34801561035657600080fd5b506103856103653660046137c4565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046137ee565b611056565b34801561044d57600080fd5b5061024561045c3660046136a2565b6111b2565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461388c565b611286565b60405161021c9190613977565b34801561050457600080fd5b506102456105133660046139f7565b611460565b34801561052457600080fd5b50610245610533366004613687565b6114ec565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613b55565b611532565b34801561059157600080fd5b506105a56105a03660046136a2565b611690565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d53660046136a2565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613687565b6116be565b34801561061357600080fd5b50610245610622366004613bc4565b611772565b61062f6118dd565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611961565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611d0d565b6106c06118dd565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611d15565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611d0d565b6107f66118dd565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611d0d565b6109086118dd565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613ca2565b905090565b504290565b610ab96118dd565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613cea565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613d0f565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611e01565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611edd565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613d37565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611d0d565b610f386118dd565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61104a611f6e565b6110546000611fef565b565b61105e6118dd565b61108b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111004690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061113c82612066565b9050600061114e82848b886000612096565b905061115f82828a88876000612343565b5050506111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6111ba611d0d565b6111c26118dd565b6111ef600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061120257611202613d5a565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156112f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611309576113096133cf565b60405190808252806020026020018201604052801561133c57816020015b60608152602001906001900390816113275790505b50905060005b82811015611459576000803086868581811061136057611360613d5a565b90506020028101906113729190613d89565b604051611380929190613dee565b600060405180830381855af49150503d80600081146113bb576040519150601f19603f3d011682016040523d82523d6000602084013e6113c0565b606091505b509150915081611426576044815110156113d957600080fd5b600481019050808060200190518101906113f39190613dfe565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b8084848151811061143957611439613d5a565b60200260200101819052505050808061145190613e7f565b915050611342565b5092915050565b6114686118dd565b611495600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6114a88a8a8a8a8a468b8b8b8b8b612485565b6111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6114f4611d0d565b6114fc6118dd565b611529600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681612604565b61153a6118dd565b611567600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106115e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b6115ef84468585856126f0565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d37858460405161163e929190613eb7565b60405180910390a361168a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106116a057600080fd5b60009182526020909120600390910201805460019091015490915082565b6116c6611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611769576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a81611fef565b61177a6118dd565b6117a7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6117b48c878585856126f0565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020018881526020016118294690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061186582612066565b9050600061187782848d896000612096565b905061188882828c89876000612343565b5050506118cf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff16611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b468260200151146119ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611a5c57611a5c613d5a565b90600052602060002090600302019050611a7b8160010154848461278d565b611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611af881600201846060015163ffffffff166127ca565b15611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611b7681600201846060015163ffffffff1661280b565b60408301515160005b81811015611c0757600085604001518281518110611b9f57611b9f613d5a565b602002602001015190506000811115611bfe57611bfe8660a001518381518110611bcb57611bcb613d5a565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50600101611b7f565b50835115611ca057611c188461289f565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611c9792919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611cfe959493929190613f5b565b60405180910390a45050505050565b611054611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261168a9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612943565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000816040516020016120799190613fb9565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156120ce57506706f05b59d3b200008560c0015167ffffffffffffffff16105b612134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106121af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036121bf5750600061233a565b6121d884848760c001516121d39190614060565b612a4f565b600087815260056020526040812054606088015192935086926121fb9190614083565b9050828110156122245780925061222183868960c0015161221c9190614060565b612a89565b91505b6000888152600560205260408120805485929061224290849061409a565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036122ca57836122b75760408701516122b79073ffffffffffffffffffffffffffffffffffffffff16333085611e01565b6122c5876020015183612ab2565b612337565b83612304576122c5338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611e01909392919063ffffffff16565b612337876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516124759d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061255a60038463ffffffff168154811061254157612541613d5a565b9060005260206000209060030201600001548284612bf3565b6125c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006125cb82612066565b905060006125e28284856060015160006001612096565b90506125f48282600080876001612343565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612681576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061277782612c0b565b9050612784878285612c46565b50505050505050565b60006127c08285856040516020016127a591906140b2565b60405160208183030381529060405280519060200120612ce4565b90505b9392505050565b6000806127d96101008461417c565b905060006127e961010085614190565b6000928352602095909552506040902054600190931b92831690921492915050565b60006128196101008361417c565b9050600061282961010084614190565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611e5b565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af115801561291f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e91906141a4565b60006129a5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612cfa9092919063ffffffff16565b8051909150156106ab57808060200190518101906129c391906141a4565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612a6382670de0b6b3a76400006141c1565b67ffffffffffffffff16612a7f84670de0b6b3a76400006141e2565b6127c3919061417c565b6000670de0b6b3a7640000612a9e83826141c1565b612a7f9067ffffffffffffffff16856141e2565b73ffffffffffffffffffffffffffffffffffffffff82163b15612b105761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612849565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b9857600080fd5b505af1158015612bac573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006127c08285856040516020016127a59190613fb9565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612079565b612c508282612d09565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612cf18584612d2d565b14949350505050565b60606127c08484600085612d72565b6000806000612d188585612f08565b91509150612d2581612f76565b509392505050565b600081815b8451811015612d2557612d5e82868381518110612d5157612d51613d5a565b60200260200101516131ca565b915080612d6a81613e7f565b915050612d32565b606082471015612e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612e82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612eab919061421f565b60006040518083038185875af1925050503d8060008114612ee8576040519150601f19603f3d011682016040523d82523d6000602084013e612eed565b606091505b5091509150612efd8282866131f9565b979650505050505050565b6000808251604103612f3e5760208301516040840151606085015160001a612f328782858561324c565b94509450505050612f6f565b8251604003612f675760208301516040840151612f5c868383613364565b935093505050612f6f565b506000905060025b9250929050565b6000816004811115612f8a57612f8a61423b565b03612f925750565b6001816004811115612fa657612fa661423b565b0361300d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156130215761302161423b565b03613088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b600381600481111561309c5761309c61423b565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561313d5761313d61423b565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b60008183106131e65760008281526020849052604090206127c3565b60008381526020839052604090206127c3565b606083156132085750816127c3565b8251156132185782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613283575060009050600361335b565b8460ff16601b1415801561329b57508460ff16601c14155b156132ac575060009050600461335b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613300573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133545760006001925092505061335b565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161339a60ff86901c601b61409a565b90506133a88782888561324c565b935093505050935093915050565b803563ffffffff811681146133ca57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613421576134216133cf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561346e5761346e6133cf565b604052919050565b600067ffffffffffffffff821115613490576134906133cf565b5060051b60200190565b600082601f8301126134ab57600080fd5b813560206134c06134bb83613476565b613427565b82815260059290921b840181019181810190868411156134df57600080fd5b8286015b848110156134fa57803583529183019183016134e3565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146133ca57600080fd5b600082601f83011261353a57600080fd5b8135602061354a6134bb83613476565b82815260059290921b8401810191818101908684111561356957600080fd5b8286015b848110156134fa5761357e81613505565b835291830191830161356d565b6000806000606084860312156135a057600080fd5b6135a9846133b6565b9250602084013567ffffffffffffffff808211156135c657600080fd5b9085019060c082880312156135da57600080fd5b6135e26133fe565b823581526020830135602082015260408301358281111561360257600080fd5b61360e8982860161349a565b604083015250613620606084016133b6565b606082015261363160808401613505565b608082015260a08301358281111561364857600080fd5b61365489828601613529565b60a0830152509350604086013591508082111561367057600080fd5b5061367d8682870161349a565b9150509250925092565b60006020828403121561369957600080fd5b6127c382613505565b6000602082840312156136b457600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156136de57600080fd5b6136e784613505565b92506020840135915060408401356136fe816136bb565b809150509250925092565b60006020828403121561371b57600080fd5b6127c3826133b6565b803567ffffffffffffffff811681146133ca57600080fd5b60008060008060008060c0878903121561375557600080fd5b61375e87613505565b955061376c60208801613505565b9450604087013593506060870135925061378860808801613724565b915061379660a088016133b6565b90509295509295509295565b600080604083850312156137b557600080fd5b50508035926020909101359150565b600080604083850312156137d757600080fd5b6137e083613505565b946020939093013593505050565b6000806000806000806000806000806101408b8d03121561380e57600080fd5b6138178b613505565b995061382560208c01613505565b985061383360408c01613505565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061385d60e08c01613724565b925061386c6101008c01613724565b915061387b6101208c016133b6565b90509295989b9194979a5092959850565b6000806020838503121561389f57600080fd5b823567ffffffffffffffff808211156138b757600080fd5b818501915085601f8301126138cb57600080fd5b8135818111156138da57600080fd5b8660208260051b85010111156138ef57600080fd5b60209290920196919550909350505050565b60005b8381101561391c578181015183820152602001613904565b8381111561168a5750506000910152565b60008151808452613945816020860160208601613901565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139ea577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139d885835161392d565b9450928501929085019060010161399e565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613a1757600080fd5b613a208b613505565b9950613a2e60208c01613505565b9850613a3c60408c01613505565b975060608b0135965060808b01359550613a5860a08c01613724565b9450613a6660c08c01613724565b9350613a7460e08c016133b6565b9250613a836101008c016133b6565b91506101208b013567ffffffffffffffff811115613aa057600080fd5b613aac8d828e0161349a565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613ad857613ad86133cf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613b1557600080fd5b8135613b236134bb82613abe565b818152846020838601011115613b3857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613b6b57600080fd5b613b7485613505565b9350613b8260208601613724565b9250613b90604086016133b6565b9150606085013567ffffffffffffffff811115613bac57600080fd5b613bb887828801613b04565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613be757600080fd5b613bf08d613505565b9b50613bfe60208e01613505565b9a50613c0c60408e01613505565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613c3660e08e01613724565b9450613c456101008e01613724565b9350613c546101208e01613724565b9250613c636101408e016133b6565b915067ffffffffffffffff6101608e01351115613c7f57600080fd5b613c908e6101608f01358f01613b04565b90509295989b509295989b509295989b565b600060208284031215613cb457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613d0757613d07613cbb565b039392505050565b600063ffffffff808316818516808303821115613d2e57613d2e613cbb565b01949350505050565b600063ffffffff808316818103613d5057613d50613cbb565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613dbe57600080fd5b83018035915067ffffffffffffffff821115613dd957600080fd5b602001915036819003821315612f6f57600080fd5b8183823760009101908152919050565b600060208284031215613e1057600080fd5b815167ffffffffffffffff811115613e2757600080fd5b8201601f81018413613e3857600080fd5b8051613e466134bb82613abe565b818152856020838501011115613e5b57600080fd5b61233a826020830160208601613901565b6020815260006127c3602083018461392d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613eb057613eb0613cbb565b5060010190565b67ffffffffffffffff831681526040602082015260006127c0604083018461392d565b600081518084526020808501945080840160005b83811015613f0a57815187529582019590820190600101613eee565b509495945050505050565b600081518084526020808501945080840160005b83811015613f0a57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f29565b85815260a060208201526000613f7460a0830187613eda565b73ffffffffffffffffffffffffffffffffffffffff80871660408501528382036060850152613fa38287613f15565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161402e60c084018267ffffffffffffffff169052565b5060e083015161404a60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613d2e57613d2e613cbb565b60008282101561409557614095613cbb565b500390565b600082198211156140ad576140ad613cbb565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526140e260e0840182613eda565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261233a8282613f15565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261418b5761418b61414d565b500490565b60008261419f5761419f61414d565b500690565b6000602082840312156141b657600080fd5b81516127c3816136bb565b600067ffffffffffffffff83811690831681811015613d0757613d07613cbb565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561421a5761421a613cbb565b500290565b60008251614231818460208701613901565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220a17e1594490c351dd225042fbaf4b4f5d0ac374b48a80a2fbd76ec203fa1d35464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461358b565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613687565b6106b0565b3480156102a057600080fd5b506102456102af3660046136a2565b61073d565b3480156102c057600080fd5b506102456102cf3660046136c9565b6107e6565b3480156102e057600080fd5b506102456102ef366004613709565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461373c565b610ab1565b34801561033657600080fd5b506102456103453660046137a2565b610f28565b34801561035657600080fd5b506103856103653660046137c4565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046137ee565b611056565b34801561044d57600080fd5b5061024561045c3660046136a2565b6111b2565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461388c565b611286565b60405161021c9190613977565b34801561050457600080fd5b506102456105133660046139f7565b611460565b34801561052457600080fd5b50610245610533366004613687565b6114ec565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613b55565b611532565b34801561059157600080fd5b506105a56105a03660046136a2565b611690565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d53660046136a2565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613687565b6116be565b34801561061357600080fd5b50610245610622366004613bc4565b611772565b61062f6118dd565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611961565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611d0d565b6106c06118dd565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611d15565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611d0d565b6107f66118dd565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611d0d565b6109086118dd565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613ca2565b905090565b504290565b610ab96118dd565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613cea565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613d0f565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611e01565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33611edd565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613d37565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611d0d565b610f386118dd565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61104a611f6e565b6110546000611fef565b565b61105e6118dd565b61108b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111004690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061113c82612066565b9050600061114e82848b886000612096565b905061115f82828a88876000612343565b5050506111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6111ba611d0d565b6111c26118dd565b6111ef600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061120257611202613d5a565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156112f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611309576113096133cf565b60405190808252806020026020018201604052801561133c57816020015b60608152602001906001900390816113275790505b50905060005b82811015611459576000803086868581811061136057611360613d5a565b90506020028101906113729190613d89565b604051611380929190613dee565b600060405180830381855af49150503d80600081146113bb576040519150601f19603f3d011682016040523d82523d6000602084013e6113c0565b606091505b509150915081611426576044815110156113d957600080fd5b600481019050808060200190518101906113f39190613dfe565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b8084848151811061143957611439613d5a565b60200260200101819052505050808061145190613e7f565b915050611342565b5092915050565b6114686118dd565b611495600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6114a88a8a8a8a8a468b8b8b8b8b612485565b6111a6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6114f4611d0d565b6114fc6118dd565b611529600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681612604565b61153a6118dd565b611567600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff16106115e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b6115ef84468585856126f0565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d37858460405161163e929190613eb7565b60405180910390a361168a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600381815481106116a057600080fd5b60009182526020909120600390910201805460019091015490915082565b6116c6611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611769576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a81611fef565b61177a6118dd565b6117a7600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6117b48c878585856126f0565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b81526020018881526020016118294690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061186582612066565b9050600061187782848d896000612096565b905061188882828c89876000612343565b5050506118cf600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff16611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b468260200151146119ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611a41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611a5c57611a5c613d5a565b90600052602060002090600302019050611a7b8160010154848461278d565b611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611af881600201846060015163ffffffff166127ca565b15611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611b7681600201846060015163ffffffff1661280b565b60408301515160005b81811015611c0757600085604001518281518110611b9f57611b9f613d5a565b602002602001015190506000811115611bfe57611bfe8660a001518381518110611bcb57611bcb613d5a565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50600101611b7f565b50835115611ca057611c188461289f565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611c9792919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611cfe959493929190613f5b565b60405180910390a45050505050565b611054611f6e565b73ffffffffffffffffffffffffffffffffffffffff8116611d92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261168a9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612943565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000816040516020016120799190613fb9565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156120ce57506706f05b59d3b200008560c0015167ffffffffffffffff16105b612134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106121af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036121bf5750600061233a565b6121d884848760c001516121d39190614060565b612a4f565b600087815260056020526040812054606088015192935086926121fb9190614083565b9050828110156122245780925061222183868960c0015161221c9190614060565b612a89565b91505b6000888152600560205260408120805485929061224290849061409a565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036122ca57836122b75760408701516122b79073ffffffffffffffffffffffffffffffffffffffff16333085611e01565b6122c5876020015183612ab2565b612337565b83612304576122c5338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611e01909392919063ffffffff16565b612337876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166128499092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516124759d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061255a60038463ffffffff168154811061254157612541613d5a565b9060005260206000209060030201600001548284612bf3565b6125c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006125cb82612066565b905060006125e28284856060015160006001612096565b90506125f48282600080876001612343565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612681576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061277782612c0b565b9050612784878285612c46565b50505050505050565b60006127c08285856040516020016127a591906140b2565b60405160208183030381529060405280519060200120612ce4565b90505b9392505050565b6000806127d96101008461417c565b905060006127e961010085614190565b6000928352602095909552506040902054600190931b92831690921492915050565b60006128196101008361417c565b9050600061282961010084614190565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611e5b565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af115801561291f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e91906141a4565b60006129a5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612cfa9092919063ffffffff16565b8051909150156106ab57808060200190518101906129c391906141a4565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612a6382670de0b6b3a76400006141c1565b67ffffffffffffffff16612a7f84670de0b6b3a76400006141e2565b6127c3919061417c565b6000670de0b6b3a7640000612a9e83826141c1565b612a7f9067ffffffffffffffff16856141e2565b73ffffffffffffffffffffffffffffffffffffffff82163b15612b105761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612849565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612b9857600080fd5b505af1158015612bac573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006127c08285856040516020016127a59190613fb9565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612079565b612c508282612d09565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612cf18584612d2d565b14949350505050565b60606127c08484600085612d72565b6000806000612d188585612f08565b91509150612d2581612f76565b509392505050565b600081815b8451811015612d2557612d5e82868381518110612d5157612d51613d5a565b60200260200101516131ca565b915080612d6a81613e7f565b915050612d32565b606082471015612e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612e82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612eab919061421f565b60006040518083038185875af1925050503d8060008114612ee8576040519150601f19603f3d011682016040523d82523d6000602084013e612eed565b606091505b5091509150612efd8282866131f9565b979650505050505050565b6000808251604103612f3e5760208301516040840151606085015160001a612f328782858561324c565b94509450505050612f6f565b8251604003612f675760208301516040840151612f5c868383613364565b935093505050612f6f565b506000905060025b9250929050565b6000816004811115612f8a57612f8a61423b565b03612f925750565b6001816004811115612fa657612fa661423b565b0361300d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156130215761302161423b565b03613088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b600381600481111561309c5761309c61423b565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561313d5761313d61423b565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b60008183106131e65760008281526020849052604090206127c3565b60008381526020839052604090206127c3565b606083156132085750816127c3565b8251156132185782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613e6c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613283575060009050600361335b565b8460ff16601b1415801561329b57508460ff16601c14155b156132ac575060009050600461335b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613300573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133545760006001925092505061335b565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161339a60ff86901c601b61409a565b90506133a88782888561324c565b935093505050935093915050565b803563ffffffff811681146133ca57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613421576134216133cf565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561346e5761346e6133cf565b604052919050565b600067ffffffffffffffff821115613490576134906133cf565b5060051b60200190565b600082601f8301126134ab57600080fd5b813560206134c06134bb83613476565b613427565b82815260059290921b840181019181810190868411156134df57600080fd5b8286015b848110156134fa57803583529183019183016134e3565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146133ca57600080fd5b600082601f83011261353a57600080fd5b8135602061354a6134bb83613476565b82815260059290921b8401810191818101908684111561356957600080fd5b8286015b848110156134fa5761357e81613505565b835291830191830161356d565b6000806000606084860312156135a057600080fd5b6135a9846133b6565b9250602084013567ffffffffffffffff808211156135c657600080fd5b9085019060c082880312156135da57600080fd5b6135e26133fe565b823581526020830135602082015260408301358281111561360257600080fd5b61360e8982860161349a565b604083015250613620606084016133b6565b606082015261363160808401613505565b608082015260a08301358281111561364857600080fd5b61365489828601613529565b60a0830152509350604086013591508082111561367057600080fd5b5061367d8682870161349a565b9150509250925092565b60006020828403121561369957600080fd5b6127c382613505565b6000602082840312156136b457600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156136de57600080fd5b6136e784613505565b92506020840135915060408401356136fe816136bb565b809150509250925092565b60006020828403121561371b57600080fd5b6127c3826133b6565b803567ffffffffffffffff811681146133ca57600080fd5b60008060008060008060c0878903121561375557600080fd5b61375e87613505565b955061376c60208801613505565b9450604087013593506060870135925061378860808801613724565b915061379660a088016133b6565b90509295509295509295565b600080604083850312156137b557600080fd5b50508035926020909101359150565b600080604083850312156137d757600080fd5b6137e083613505565b946020939093013593505050565b6000806000806000806000806000806101408b8d03121561380e57600080fd5b6138178b613505565b995061382560208c01613505565b985061383360408c01613505565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061385d60e08c01613724565b925061386c6101008c01613724565b915061387b6101208c016133b6565b90509295989b9194979a5092959850565b6000806020838503121561389f57600080fd5b823567ffffffffffffffff808211156138b757600080fd5b818501915085601f8301126138cb57600080fd5b8135818111156138da57600080fd5b8660208260051b85010111156138ef57600080fd5b60209290920196919550909350505050565b60005b8381101561391c578181015183820152602001613904565b8381111561168a5750506000910152565b60008151808452613945816020860160208601613901565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156139ea577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526139d885835161392d565b9450928501929085019060010161399e565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613a1757600080fd5b613a208b613505565b9950613a2e60208c01613505565b9850613a3c60408c01613505565b975060608b0135965060808b01359550613a5860a08c01613724565b9450613a6660c08c01613724565b9350613a7460e08c016133b6565b9250613a836101008c016133b6565b91506101208b013567ffffffffffffffff811115613aa057600080fd5b613aac8d828e0161349a565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613ad857613ad86133cf565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613b1557600080fd5b8135613b236134bb82613abe565b818152846020838601011115613b3857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613b6b57600080fd5b613b7485613505565b9350613b8260208601613724565b9250613b90604086016133b6565b9150606085013567ffffffffffffffff811115613bac57600080fd5b613bb887828801613b04565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613be757600080fd5b613bf08d613505565b9b50613bfe60208e01613505565b9a50613c0c60408e01613505565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613c3660e08e01613724565b9450613c456101008e01613724565b9350613c546101208e01613724565b9250613c636101408e016133b6565b915067ffffffffffffffff6101608e01351115613c7f57600080fd5b613c908e6101608f01358f01613b04565b90509295989b509295989b509295989b565b600060208284031215613cb457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613d0757613d07613cbb565b039392505050565b600063ffffffff808316818516808303821115613d2e57613d2e613cbb565b01949350505050565b600063ffffffff808316818103613d5057613d50613cbb565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613dbe57600080fd5b83018035915067ffffffffffffffff821115613dd957600080fd5b602001915036819003821315612f6f57600080fd5b8183823760009101908152919050565b600060208284031215613e1057600080fd5b815167ffffffffffffffff811115613e2757600080fd5b8201601f81018413613e3857600080fd5b8051613e466134bb82613abe565b818152856020838501011115613e5b57600080fd5b61233a826020830160208601613901565b6020815260006127c3602083018461392d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613eb057613eb0613cbb565b5060010190565b67ffffffffffffffff831681526040602082015260006127c0604083018461392d565b600081518084526020808501945080840160005b83811015613f0a57815187529582019590820190600101613eee565b509495945050505050565b600081518084526020808501945080840160005b83811015613f0a57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f29565b85815260a060208201526000613f7460a0830187613eda565b73ffffffffffffffffffffffffffffffffffffffff80871660408501528382036060850152613fa38287613f15565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161402e60c084018267ffffffffffffffff169052565b5060e083015161404a60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613d2e57613d2e613cbb565b60008282101561409557614095613cbb565b500390565b600082198211156140ad576140ad613cbb565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526140e260e0840182613eda565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261233a8282613f15565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261418b5761418b61414d565b500490565b60008261419f5761419f61414d565b500690565b6000602082840312156141b657600080fd5b81516127c3816136bb565b600067ffffffffffffffff83811690831681811015613d0757613d07613cbb565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561421a5761421a613cbb565b500290565b60008251614231818460208701613901565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220a17e1594490c351dd225042fbaf4b4f5d0ac374b48a80a2fbd76ec203fa1d35464736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/LpTokenFactory.json b/deployments/goerli/LpTokenFactory.json index 2134393f..412a1a44 100644 --- a/deployments/goerli/LpTokenFactory.json +++ b/deployments/goerli/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "530f09405f9b997fd4129db468c279d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x24b04b8aacaaf1a4a0719117b29c9c3647b1f479c5ac2a60f5ff1bb6d839c238\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x24b04b8aacaaf1a4a0719117b29c9c3647b1f479c5ac2a60f5ff1bb6d839c238\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220ae1af4c6ba3b3ddfee5c0c252ca16095fdb12c3dc044ba3635160120a67b04a064736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212205257870f7ee952c4687aa9c1fe4b37ed2a1c8dda16b3b45b15c1a60fa462ee5c64736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220ae1af4c6ba3b3ddfee5c0c252ca16095fdb12c3dc044ba3635160120a67b04a064736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212205257870f7ee952c4687aa9c1fe4b37ed2a1c8dda16b3b45b15c1a60fa462ee5c64736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/ZkSync_Adapter.json b/deployments/goerli/ZkSync_Adapter.json index 07a3d30f..e12287f2 100644 --- a/deployments/goerli/ZkSync_Adapter.json +++ b/deployments/goerli/ZkSync_Adapter.json @@ -221,7 +221,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "4972f5cae7c6e9deea3ed342ae0a0eeb", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"}],\"name\":\"ZkSyncMessageRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ergsLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkErc20Bridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkEthBridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkSync\",\"outputs\":[{\"internalType\":\"contract ZkSyncLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to ZkSync.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/ZkSync_Adapter.sol\":\"ZkSync_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\n// SPDX-License-Identifier: MIT OR Apache-2.0\\n\\n\\n\\n/// @notice Priority Operation container\\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\\nstruct PriorityOperation {\\n bytes32 canonicalTxHash;\\n uint64 expirationBlock;\\n uint192 layer2Tip;\\n}\\n\\n/// @notice A structure that stores all priority operations by ID\\n/// used for easy acceptance as an argument in functions\\nstruct StoredOperations {\\n mapping(uint64 => PriorityOperation) inner;\\n}\\n\\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\\nenum OpTree {\\n Full,\\n Rollup\\n}\\n\\n/// @notice Priority operations queue type\\nenum QueueType {\\n Deque,\\n HeapBuffer,\\n Heap\\n}\\n\",\"keccak256\":\"0x2ef35aee4840baf29036547cd7ec428889eaa17786c621d772a1bd4940ada2c2\",\"license\":\"MIT OR Apache-2.0\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/ZkSync_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// Importing `Operations` contract which has the `QueueType` type\\nimport \\\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\\\";\\n\\ninterface ZkSyncLike {\\n function requestL2Transaction(\\n address _contractAddressL2,\\n bytes calldata _calldata,\\n uint256 _ergsLimit,\\n bytes[] calldata _factoryDeps,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\ninterface ZkBridgeLike {\\n function deposit(\\n address _to,\\n address _l1Token,\\n uint256 _amount,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to ZkSync.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract ZkSync_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\\n \\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\\n // (ergs = gas on ZkSync) and the calldata length. More details here:\\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\\n\\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\\n uint256 public immutable l2GasPrice = 1e9;\\n\\n uint32 public immutable ergsLimit = 1_000_000;\\n\\n // Hardcode WETH address for L1 since it will not change:\\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\\n\\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\\n // redeployed in the event that the following addresses change.\\n\\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\\n\\n event ZkSyncMessageRelayed(bytes32 txHash);\\n\\n /**\\n * @notice Send cross-chain message to target on ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \\n * will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // Parameters passed to requestL2Transaction:\\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\\n // same way as on Ethereum.\\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\\n // QueueType.Deque should always be supplied.\\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\\n target,\\n message,\\n ergsLimit,\\n new bytes[](0),\\n QueueType.Deque\\n );\\n\\n emit MessageRelayed(target, message);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Bridge tokens to ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \\n * or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\\n // cost.\\n bytes32 txHash;\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2GasPrice * ergsLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x48c1425675f529b41bc65ba300b2c0fd5b9aa3dd5e4a859fb93e12bc878f5740\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"}],\"name\":\"ZkSyncMessageRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ergsLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkErc20Bridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkEthBridge\",\"outputs\":[{\"internalType\":\"contract ZkBridgeLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zkSync\",\"outputs\":[{\"internalType\":\"contract ZkSyncLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to ZkSync.This contract must hold at least getL1CallValue() amount of ETH to send a message or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to ZkSync.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/ZkSync_Adapter.sol\":\"ZkSync_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\n// SPDX-License-Identifier: MIT OR Apache-2.0\\n\\n\\n\\n/// @notice Priority Operation container\\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\\nstruct PriorityOperation {\\n bytes32 canonicalTxHash;\\n uint64 expirationBlock;\\n uint192 layer2Tip;\\n}\\n\\n/// @notice A structure that stores all priority operations by ID\\n/// used for easy acceptance as an argument in functions\\nstruct StoredOperations {\\n mapping(uint64 => PriorityOperation) inner;\\n}\\n\\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\\nenum OpTree {\\n Full,\\n Rollup\\n}\\n\\n/// @notice Priority operations queue type\\nenum QueueType {\\n Deque,\\n HeapBuffer,\\n Heap\\n}\\n\",\"keccak256\":\"0x2ef35aee4840baf29036547cd7ec428889eaa17786c621d772a1bd4940ada2c2\",\"license\":\"MIT OR Apache-2.0\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/ZkSync_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// Importing `Operations` contract which has the `QueueType` type\\nimport \\\"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\\\";\\n\\ninterface ZkSyncLike {\\n function requestL2Transaction(\\n address _contractAddressL2,\\n bytes calldata _calldata,\\n uint256 _ergsLimit,\\n bytes[] calldata _factoryDeps,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\ninterface ZkBridgeLike {\\n function deposit(\\n address _to,\\n address _l1Token,\\n uint256 _amount,\\n QueueType _queueType\\n ) external payable returns (bytes32 txHash);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to ZkSync.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract ZkSync_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\\n \\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\\n // (ergs = gas on ZkSync) and the calldata length. More details here:\\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\\n\\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\\n uint256 public immutable l2GasPrice = 1e9;\\n\\n uint32 public immutable ergsLimit = 1_000_000;\\n\\n // Hardcode WETH address for L1 since it will not change:\\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\\n\\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\\n // redeployed in the event that the following addresses change.\\n\\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\\n\\n event ZkSyncMessageRelayed(bytes32 txHash);\\n\\n /**\\n * @notice Send cross-chain message to target on ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \\n * will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // Parameters passed to requestL2Transaction:\\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\\n // same way as on Ethereum.\\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\\n // QueueType.Deque should always be supplied.\\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\\n target,\\n message,\\n ergsLimit,\\n new bytes[](0),\\n QueueType.Deque\\n );\\n\\n emit MessageRelayed(target, message);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Bridge tokens to ZkSync.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \\n * or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 txBaseCost = _contractHasSufficientEthBalance();\\n\\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\\n // cost.\\n bytes32 txHash;\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n emit ZkSyncMessageRelayed(txHash);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2GasPrice * ergsLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x48c1425675f529b41bc65ba300b2c0fd5b9aa3dd5e4a859fb93e12bc878f5740\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052633b9aca00608052620f424060a05273b4fbf271143f4fbf7b91a5ded31805e42b2208d660c05273a0f968eba6bbd08f28dc061c7856c1572598339560e052737786255495348c08f82c09c82352019fade3bf296101005273cbebcd41ceabbc85da9bb67527f58d69ad4dfff56101205234801561008257600080fd5b5060805160a05160c05160e05161010051610120516110e46101106000396000818161018c01526103b70152600081816102280152818161048801526104ea0152600081816101c0015261062d01526000818160d5015281816102c4015261034401526000818161012e0152818161026901526106570152600081816101f4015261028b01526110e46000f3fe6080604052600436106100965760003560e01c80636bbc6c3d116100695780639ae366851161004e5780639ae36685146101e2578063bb3e04b514610216578063e6eb8ade1461024a57600080fd5b80636bbc6c3d1461017a5780637c19f005146101ae57600080fd5b806308f1ed151461009b578063146bf4b1146100c35780633ab307681461011c57806352c8c75c14610165575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b34801561012857600080fd5b506101507f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b610178610173366004610c79565b6102b4565b005b34801561018657600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ba57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ee57600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561022257600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b610178610258366004610cf5565b610608565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e04565b905090565b60006102be610784565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361046c576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039d57600080fd5b505af11580156103b1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637f63f61885846103fd9190610e41565b8560008860006040518663ffffffff1660e01b81526004016104229493929190610e94565b60206040518083038185885af1158015610440573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104659190610ed6565b905061056e565b6104ad73ffffffffffffffffffffffffffffffffffffffff87167f000000000000000000000000000000000000000000000000000000000000000086610802565b6040517f7f63f61800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637f63f6189084906105289087908b908a90600090600401610e94565b60206040518083038185885af1158015610546573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061056b9190610ed6565b90505b6040805173ffffffffffffffffffffffffffffffffffffffff888116825287811660208301528183018790528516606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a1505050505050565b6000610612610784565b9050600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663b4848df58386867f0000000000000000000000000000000000000000000000000000000000000000866040519080825280602002602001820160405280156106aa57816020015b60608152602001906001900390816106955790505b5060006040518763ffffffff1660e01b81526004016106cd959493929190610f65565b60206040518083038185885af11580156106eb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107109190610ed6565b90507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4848460405161074392919061102e565b60405180910390a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a150505050565b600061078e61025d565b9050804710156107ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089d9190610ed6565b6108a79190610e41565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061093790859061093d565b50505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4e9092919063ffffffff16565b805190915015610a4957808060200190518101906109bd919061105d565b610a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107f6565b505050565b6060610a5d8484600085610a67565b90505b9392505050565b606082471015610af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107f6565b73ffffffffffffffffffffffffffffffffffffffff85163b610b77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107f6565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba0919061107f565b60006040518083038185875af1925050503d8060008114610bdd576040519150601f19603f3d011682016040523d82523d6000602084013e610be2565b606091505b5091509150610bf2828286610bfd565b979650505050505050565b60608315610c0c575081610a60565b825115610c1c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f6919061109b565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7457600080fd5b919050565b60008060008060808587031215610c8f57600080fd5b610c9885610c50565b9350610ca660208601610c50565b925060408501359150610cbb60608601610c50565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0857600080fd5b610d1183610c50565b9150602083013567ffffffffffffffff80821115610d2e57600080fd5b818501915085601f830112610d4257600080fd5b813581811115610d5457610d54610cc6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9a57610d9a610cc6565b81604052828152886020848701011115610db357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e3c57610e3c610dd5565b500290565b60008219821115610e5457610e54610dd5565b500190565b60038110610e90577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b73ffffffffffffffffffffffffffffffffffffffff8581168252841660208201526040810183905260808101610ecd6060830184610e59565b95945050505050565b600060208284031215610ee857600080fd5b5051919050565b60005b83811015610f0a578181015183820152602001610ef2565b838111156109375750506000910152565b60008151808452610f33816020860160208601610eef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff861681526000602060a081840152610f9560a0840188610f1b565b63ffffffff871660408501528381036060850152855180825282820190600581901b8301840184890160005b8381101561100d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552610ffb838351610f1b565b94870194925090860190600101610fc1565b505080955050505050506110246080830184610e59565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5d6040830184610f1b565b60006020828403121561106f57600080fd5b81518015158114610a6057600080fd5b60008251611091818460208701610eef565b9190910192915050565b602081526000610a606020830184610f1b56fea2646970667358221220f2d66b26ee0770e83f57c27ccb80c0dc4c72c5b22119ead93d7474349789c95264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80636bbc6c3d116100695780639ae366851161004e5780639ae36685146101e2578063bb3e04b514610216578063e6eb8ade1461024a57600080fd5b80636bbc6c3d1461017a5780637c19f005146101ae57600080fd5b806308f1ed151461009b578063146bf4b1146100c35780633ab307681461011c57806352c8c75c14610165575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b34801561012857600080fd5b506101507f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b610178610173366004610c79565b6102b4565b005b34801561018657600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ba57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ee57600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561022257600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b610178610258366004610cf5565b610608565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e04565b905090565b60006102be610784565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361046c576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039d57600080fd5b505af11580156103b1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637f63f61885846103fd9190610e41565b8560008860006040518663ffffffff1660e01b81526004016104229493929190610e94565b60206040518083038185885af1158015610440573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104659190610ed6565b905061056e565b6104ad73ffffffffffffffffffffffffffffffffffffffff87167f000000000000000000000000000000000000000000000000000000000000000086610802565b6040517f7f63f61800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637f63f6189084906105289087908b908a90600090600401610e94565b60206040518083038185885af1158015610546573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061056b9190610ed6565b90505b6040805173ffffffffffffffffffffffffffffffffffffffff888116825287811660208301528183018790528516606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a1505050505050565b6000610612610784565b9050600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663b4848df58386867f0000000000000000000000000000000000000000000000000000000000000000866040519080825280602002602001820160405280156106aa57816020015b60608152602001906001900390816106955790505b5060006040518763ffffffff1660e01b81526004016106cd959493929190610f65565b60206040518083038185885af11580156106eb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906107109190610ed6565b90507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4848460405161074392919061102e565b60405180910390a16040518181527f82e577407245f8e8c446b39602dae3fffacbc21172a51c88525e050063929b2f9060200160405180910390a150505050565b600061078e61025d565b9050804710156107ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089d9190610ed6565b6108a79190610e41565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061093790859061093d565b50505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4e9092919063ffffffff16565b805190915015610a4957808060200190518101906109bd919061105d565b610a49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107f6565b505050565b6060610a5d8484600085610a67565b90505b9392505050565b606082471015610af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107f6565b73ffffffffffffffffffffffffffffffffffffffff85163b610b77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107f6565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba0919061107f565b60006040518083038185875af1925050503d8060008114610bdd576040519150601f19603f3d011682016040523d82523d6000602084013e610be2565b606091505b5091509150610bf2828286610bfd565b979650505050505050565b60608315610c0c575081610a60565b825115610c1c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f6919061109b565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7457600080fd5b919050565b60008060008060808587031215610c8f57600080fd5b610c9885610c50565b9350610ca660208601610c50565b925060408501359150610cbb60608601610c50565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0857600080fd5b610d1183610c50565b9150602083013567ffffffffffffffff80821115610d2e57600080fd5b818501915085601f830112610d4257600080fd5b813581811115610d5457610d54610cc6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9a57610d9a610cc6565b81604052828152886020848701011115610db357600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e3c57610e3c610dd5565b500290565b60008219821115610e5457610e54610dd5565b500190565b60038110610e90577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b73ffffffffffffffffffffffffffffffffffffffff8581168252841660208201526040810183905260808101610ecd6060830184610e59565b95945050505050565b600060208284031215610ee857600080fd5b5051919050565b60005b83811015610f0a578181015183820152602001610ef2565b838111156109375750506000910152565b60008151808452610f33816020860160208601610eef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff861681526000602060a081840152610f9560a0840188610f1b565b63ffffffff871660408501528381036060850152855180825282820190600581901b8301840184890160005b8381101561100d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552610ffb838351610f1b565b94870194925090860190600101610fc1565b505080955050505050506110246080830184610e59565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5d6040830184610f1b565b60006020828403121561106f57600080fd5b81518015158114610a6057600080fd5b60008251611091818460208701610eef565b9190910192915050565b602081526000610a606020830184610f1b56fea2646970667358221220f2d66b26ee0770e83f57c27ccb80c0dc4c72c5b22119ead93d7474349789c95264736f6c634300080d0033", "devdoc": { diff --git a/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json b/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json index 343a79c6..870df190 100644 --- a/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json +++ b/deployments/goerli/solcInputs/0c0f7cf4c33344752a752d4aad8f0613.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json b/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json index 4746a4a5..6cdc08c4 100644 --- a/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json +++ b/deployments/goerli/solcInputs/4972f5cae7c6e9deea3ed342ae0a0eeb.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -26,76 +26,76 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n address public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n address public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _zkErc20Bridge,\n address _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(address _zkErc20Bridge, address _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n ZkBridgeLike(relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge)\n .withdraw(\n hubPool, \n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? address(0) : relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(address _zkErc20Bridge, address _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n address public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n address public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _zkErc20Bridge,\n address _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(address _zkErc20Bridge, address _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n ZkBridgeLike(relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge)\n .withdraw(\n hubPool, \n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? address(0) : relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(address _zkErc20Bridge, address _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -110,13 +110,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -125,58 +125,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n \n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n \n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message \n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message \n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -185,22 +185,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json b/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json index d083c08e..7aa31929 100644 --- a/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json +++ b/deployments/goerli/solcInputs/b9d6747074e2e4e0305d51ac3373cf9e.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,58 +131,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -191,25 +191,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n // Addresses that can claim on user's behalf. Useful to get around the requirement that claim recipient\n // must also be claimer.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender or claimer must be whitelisted.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n if (!whitelistedClaimers[msg.sender]) {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender or caller must be whitelisted.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(whitelistedClaimers[msg.sender] || _claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n // Addresses that can claim on user's behalf. Useful to get around the requirement that claim recipient\n // must also be claimer.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender or claimer must be whitelisted.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n if (!whitelistedClaimers[msg.sender]) {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender or caller must be whitelisted.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(whitelistedClaimers[msg.sender] || _claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json b/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json index 6554b649..c1ab45cf 100644 --- a/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json +++ b/deployments/goerli/solcInputs/e3638a53e1e5b7b0c7a6b5bbdc94b1ad.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -26,13 +26,13 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -74,37 +74,37 @@ "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/interfaces/IERC1271.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title MockERC1271\n * @notice Implements mocked ERC1271 contract for testing.\n */\ncontract MockERC1271 is IERC1271, Ownable {\n constructor(address originalOwner) {\n transferOwnership(originalOwner);\n }\n\n function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) {\n return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);\n }\n}\n" }, "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "contracts/BondToken.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./interfaces/HubPoolInterface.sol\";\nimport \"./external/WETH9.sol\";\n\ninterface ExtendedHubPoolInterface is HubPoolInterface {\n // Specify the automatically-implemented rootBundleProposal() getter.\n function rootBundleProposal() external pure returns (HubPoolInterface.RootBundle memory);\n}\n\n/**\n * @notice Across Bond Token (ABT).\n * ABT is a simple deposit contract based on WETH9. ABT is issued proportionally to any address that deposits Ether. It\n * imposes address-based permissioning on the WETH9 transferFrom() function in order to constrain the movement of ABT\n * into the Across v2 HubPool contract. When configured as the required HubPool bond token, ABT can dramatically reduce\n * the attack surface of the HubPool by requiring that addresses are explicitly approved before they can successfully\n * submit a root bundle proposal. The address-based permissioning does not constrain transfers that are needed to dispute\n * a root bundle proposal, so the ability of decentralised/unknown actors to dispute is unaffected.\n */\ncontract BondToken is WETH9, Ownable {\n using Address for address;\n\n ExtendedHubPoolInterface public immutable hubPool;\n\n /**\n * @notice Addresses that are permitted to make HubPool root bundle proposals.\n */\n mapping(address => bool) public proposers;\n\n /**\n * @notice Emitted on proposer permissions update.\n */\n event ProposerModified(address proposer, bool enabled);\n\n /**\n * @notice BondToken constructor.\n * @param _hubPool Address of the target HubPool contract.\n */\n constructor(ExtendedHubPoolInterface _hubPool) {\n name = \"Across Bond Token\";\n symbol = \"ABT\";\n hubPool = _hubPool;\n }\n\n /**\n * @notice Enable or disable an address as an allowed proposer. Emits a \"ProposerModified\" event on completion.\n * @param proposer Proposer address to modify.\n * @param enabled Boolean controlling whether the address is permitted to propose.\n */\n function setProposer(address proposer, bool enabled) external onlyOwner {\n proposers[proposer] = enabled;\n emit ProposerModified(proposer, enabled);\n }\n\n /**\n * @notice Transfer amt from src to dst. Prevents unauthorised root bundle proposals by blocking transfers to the\n * HubPool under the following conditions:\n * - The src address is not a pre-approved proposer, *and*\n * - The src address is the current proposer of a HubPool root bundle.\n * Falls back to the base implementation after verifying that the transfer is permitted.\n * @dev The require(..., \"Transfer not permitted\") statement is dependent on the internal ordering of HubPool\n * proposedRootBundle state variable updates, relative to calling bondToken.safeTransferFrom(). Changing the order\n * of HubPool actions may invalidate this verification. BondToken tests are implemented to detect this.\n * @param src Source address.\n * @param dst Destination address.\n * @param amt Amount to transfer.\n * @return True on success.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amt\n ) public override returns (bool) {\n if (dst == address(hubPool)) {\n require(proposers[src] || hubPool.rootBundleProposal().proposer != src, \"Transfer not permitted\");\n }\n return super.transferFrom(src, dst, amt);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./interfaces/HubPoolInterface.sol\";\nimport \"./external/WETH9.sol\";\n\ninterface ExtendedHubPoolInterface is HubPoolInterface {\n // Specify the automatically-implemented rootBundleProposal() getter.\n function rootBundleProposal() external pure returns (HubPoolInterface.RootBundle memory);\n}\n\n/**\n * @notice Across Bond Token (ABT).\n * ABT is a simple deposit contract based on WETH9. ABT is issued proportionally to any address that deposits Ether. It\n * imposes address-based permissioning on the WETH9 transferFrom() function in order to constrain the movement of ABT\n * into the Across v2 HubPool contract. When configured as the required HubPool bond token, ABT can dramatically reduce\n * the attack surface of the HubPool by requiring that addresses are explicitly approved before they can successfully\n * submit a root bundle proposal. The address-based permissioning does not constrain transfers that are needed to dispute\n * a root bundle proposal, so the ability of decentralised/unknown actors to dispute is unaffected.\n */\ncontract BondToken is WETH9, Ownable {\n using Address for address;\n\n ExtendedHubPoolInterface public immutable hubPool;\n\n /**\n * @notice Addresses that are permitted to make HubPool root bundle proposals.\n */\n mapping(address => bool) public proposers;\n\n /**\n * @notice Emitted on proposer permissions update.\n */\n event ProposerModified(address proposer, bool enabled);\n\n /**\n * @notice BondToken constructor.\n * @param _hubPool Address of the target HubPool contract.\n */\n constructor(ExtendedHubPoolInterface _hubPool) {\n name = \"Across Bond Token\";\n symbol = \"ABT\";\n hubPool = _hubPool;\n }\n\n /**\n * @notice Enable or disable an address as an allowed proposer. Emits a \"ProposerModified\" event on completion.\n * @param proposer Proposer address to modify.\n * @param enabled Boolean controlling whether the address is permitted to propose.\n */\n function setProposer(address proposer, bool enabled) external onlyOwner {\n proposers[proposer] = enabled;\n emit ProposerModified(proposer, enabled);\n }\n\n /**\n * @notice Transfer amt from src to dst. Prevents unauthorised root bundle proposals by blocking transfers to the\n * HubPool under the following conditions:\n * - The src address is not a pre-approved proposer, *and*\n * - The src address is the current proposer of a HubPool root bundle.\n * Falls back to the base implementation after verifying that the transfer is permitted.\n * @dev The require(..., \"Transfer not permitted\") statement is dependent on the internal ordering of HubPool\n * proposedRootBundle state variable updates, relative to calling bondToken.safeTransferFrom(). Changing the order\n * of HubPool actions may invalidate this verification. BondToken tests are implemented to detect this.\n * @param src Source address.\n * @param dst Destination address.\n * @param amt Amount to transfer.\n * @return True on success.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amt\n ) public override returns (bool) {\n if (dst == address(hubPool)) {\n require(proposers[src] || hubPool.rootBundleProposal().proposer != src, \"Transfer not permitted\");\n }\n return super.transferFrom(src, dst, amt);\n }\n}\n" }, "contracts/interfaces/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/external/WETH9.sol": { "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n/**\n * Copyright (C) 2015, 2016, 2017 Dapphub\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n/**\n * Imported as at commit 33d01d471437e1ab6861e4545ea4bb3895fd4d74 from:\n * UMAprotocol/protocol/packages/core/contracts/financial-templates/common/WETH9.sol\n * Changes applied post-import:\n * - Corrected SPDX-License-Identifier & reinstated GPLv3 license header.\n * - Permit transferFrom() to be overridden by marking it virtual.\n */\n\npragma solidity ^0.8.0;\n\ncontract WETH9 {\n string public name = \"Wrapped Ether\";\n string public symbol = \"WETH\";\n uint8 public decimals = 18;\n\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n receive() external payable {\n deposit();\n }\n\n fallback() external payable {\n deposit();\n }\n\n function deposit() public payable {\n balanceOf[msg.sender] += msg.value;\n emit Deposit(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) public {\n require(balanceOf[msg.sender] >= wad);\n balanceOf[msg.sender] -= wad;\n payable(msg.sender).transfer(wad);\n emit Withdrawal(msg.sender, wad);\n }\n\n function totalSupply() public view returns (uint256) {\n return address(this).balance;\n }\n\n function approve(address guy, uint256 wad) public returns (bool) {\n allowance[msg.sender][guy] = wad;\n emit Approval(msg.sender, guy, wad);\n return true;\n }\n\n function transfer(address dst, uint256 wad) public returns (bool) {\n return transferFrom(msg.sender, dst, wad);\n }\n\n /**\n * @dev Local change: marked virtual to allow overriding.\n */\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) public virtual returns (bool) {\n require(balanceOf[src] >= wad);\n\n if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) {\n require(allowance[src][msg.sender] >= wad);\n allowance[src][msg.sender] -= wad;\n }\n\n balanceOf[src] -= wad;\n balanceOf[dst] += wad;\n\n emit Transfer(src, dst, wad);\n\n return true;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../interfaces/HubPoolInterface.sol\";\nimport \"../interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowFill,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowFill, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../interfaces/HubPoolInterface.sol\";\nimport \"../interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowFill,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowFill, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./interfaces/HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./interfaces/HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index);\n }\n}\n" }, "contracts/interfaces/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n // This tracks the number of identical refunds that have been requested.\n // The intention is to allow an off-chain system to know when this could be a duplicate and ensure that the other\n // requests are known and accounted for.\n mapping(bytes32 => uint256) public refundsRequested;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n // Note: this needs to be larger than the max transfer size to ensure that all slow fills are fillable, even if\n // their fees are negative.\n // It's important that it isn't too large, however, as it should be multipliable by ~2e18 without overflowing.\n // 1e40 * 2e18 = 2e58 << 2^255 ~= 5e76\n uint256 public constant SLOW_FILL_MAX_TOKENS_TO_SEND = 1e40;\n\n // Set max payout adjustment to something\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 indexed destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n event RefundRequested(\n address indexed relayer,\n address refundToken,\n uint256 amount,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n uint256 fillBlock,\n uint256 previousIdenticalRequests\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n /**\n * @notice Represents data used to fill a deposit.\n * @param relay Relay containing original data linked to deposit. Contains fields that can be\n * overridden by other parameters in the RelayExecution struct.\n * @param relayHash Hash of the relay data.\n * @param updatedRelayerFeePct Actual relayer fee pct to use for this relay.\n * @param updatedRecipient Actual recipient to use for this relay.\n * @param updatedMessage Actual message to use for this relay.\n * @param repaymentChainId Chain ID of the network that the relayer will receive refunds on.\n * @param maxTokensToSend Max number of tokens to pull from relayer.\n * @param maxCount Max count to protect the relayer from frontrunning.\n * @param slowFill Whether this is a slow fill.\n * @param payoutAdjustmentPct Adjustment to the payout amount. Can be used to increase or decrease the payout to\n * allow for rewards or penalties. Used in slow fills.\n */\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * @notice Packs together information to include in FilledRelay event.\n * @dev This struct is emitted as opposed to its constituent parameters due to the limit on number of\n * parameters in an event.\n * @param recipient Recipient of the relayed funds.\n * @param message Message included in the relay.\n * @param relayerFeePct Relayer fee pct used for this relay.\n * @param isSlowRelay Whether this is a slow relay.\n * @param payoutAdjustmentPct Adjustment to the payout amount.\n */\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects `deposit()` but not `speedUpDeposit()`, so that existing deposits can be sped up and still\n * relayed.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n /**\n * @notice Pauses fill-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects fillRelayWithUpdatedDeposit() and fillRelay().\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit FundsDeposited(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(SignedMath.abs(updatedRelayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpDeposit().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Caller signals to the system that they want a refund on this chain, which they set as the\n * `repaymentChainId` on the original fillRelay() call on the `destinationChainId`. An observer should be\n * be able to 1-to-1 match the emitted RefundRequested event with the FilledRelay event on the `destinationChainId`.\n * @dev This function could be used to artificially inflate the `fillCounter`, allowing the caller to \"frontrun\"\n * and cancel pending fills in the mempool. This would in the worst case censor fills at the cost of the caller's\n * gas costs. We don't view this as a major issue as the fill can be resubmitted and obtain the same incentive,\n * since incentives are based on validated refunds and would ignore these censoring attempts. This is no\n * different from calling `fillRelay` and setting msg.sender = recipient.\n * @dev Caller needs to pass in `fillBlock` that the FilledRelay event was emitted on the `destinationChainId`.\n * This is to make it hard to request a refund before a fill has been mined and to make lookups of the original\n * fill as simple as possible.\n * @param refundToken This chain's token equivalent for original fill destination token.\n * @param amount Original deposit amount.\n * @param originChainId Original origin chain ID.\n * @param destinationChainId Original destination chain ID.\n * @param realizedLpFeePct Original realized LP fee %.\n * @param depositId Original deposit ID.\n * @param maxCount Max count to protect the refund recipient from frontrunning.\n */\n function requestRefund(\n address refundToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 depositId,\n uint256 fillBlock,\n uint256 maxCount\n ) external nonReentrant {\n // Prevent unrealistic amounts from increasing fill counter too high.\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[refundToken] <= maxCount, \"Above max count\");\n\n // Track duplicate refund requests.\n bytes32 refundHash = keccak256(\n abi.encode(\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock\n )\n );\n\n // Track duplicate requests so that an offchain actor knows if an identical request has already been made.\n // If so, it can check to ensure that that request was thrown out as invalid before honoring the duplicate.\n // In particular, this is meant to handle odd cases where an initial request is invalidated based on\n // timing, but can be validated by a later, identical request.\n uint256 previousIdenticalRequests = refundsRequested[refundHash]++;\n\n // Refund will take tokens out of this pool, increment the fill counter. This function should only be\n // called if a relayer from destinationChainId wants to take a refund on this chain, a different chain.\n // This type of repayment should only be possible for full fills, so the starting fill amount should\n // always be 0. Also, just like in _fillRelay we should revert if the first fill pre fees rounds to 0,\n // and in this case `amount` == `fillAmountPreFees`.\n require(amount > 0, \"Amount must be > 0\");\n _updateCountFromFill(\n 0,\n true, // The refund is being requested here, so it is local.\n amount,\n realizedLpFeePct,\n refundToken,\n false // Slow fills should never match with a Refund. This should be enforced by off-chain bundle builders.\n );\n\n emit RefundRequested(\n // Set caller as relayer. If caller is not relayer from destination chain that originally sent\n // fill, then off-chain validator should discard this refund attempt.\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock,\n previousIdenticalRequests\n );\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: SLOW_FILL_MAX_TOKENS_TO_SEND,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n // This is equivalent to the amount to be sent by the relayer before fees have been taken out.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If fill amount minus fees, which is possible with small fill amounts and negative fees, then\n // revert.\n require(fillAmountPreFees > 0, \"fill amount pre fees is 0\");\n\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n }\n\n // Apply post-fees computation to amount that relayer will send to user. Rounding errors are possible\n // when computing fillAmountPreFees and then amountToSend, and we just want to enforce that\n // the error added to amountToSend is consistently applied to partial and full fills.\n uint256 amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n // This can only happen in a slow fill, where the contract is funding the relay.\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Allow the payout adjustment to go up to 1000% (i.e. 11x).\n // This is a sanity check to ensure the payouts do not grow too large via some sort of issue in bundle\n // construction.\n require(relayExecution.payoutAdjustmentPct <= 100e18, \"payoutAdjustmentPct too large\");\n\n // Note: since _computeAmountPostFees is typically intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n\n // Note: this error should never happen, since the maxTokensToSend is expected to be set much higher than\n // the amount, but it is here as a sanity check.\n require(amountToSend <= relayExecution.maxTokensToSend, \"Somehow hit maxTokensToSend!\");\n }\n\n // Since the first partial fill is used to update the fill counter for the entire refund amount, we don't have\n // a simple way to handle the case where follow-up partial fills take repayment on different chains. We'd\n // need a way to decrement the fill counter in this case (or increase deposit counter) to ensure that users\n // have adequate frontrunning protections.\n // Instead of adding complexity, we require that all partial fills set repayment chain equal to destination chain.\n // Note: .slowFill is checked because slow fills set repaymentChainId to 0.\n bool localRepayment = relayExecution.repaymentChainId == relayExecution.relay.destinationChainId;\n require(\n localRepayment || relayExecution.relay.amount == fillAmountPreFees || relayExecution.slowFill,\n \"invalid repayment chain\"\n );\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n localRepayment,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n bool localRepayment,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, a first partial fill with repayment on another chain, or a partial fill has already happened, do nothing, as these\n // should not impact the count. Initial 0-fills will not reach this part of the code.\n if (useContractFunds || startingFillAmount > 0 || !localRepayment) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n // This tracks the number of identical refunds that have been requested.\n // The intention is to allow an off-chain system to know when this could be a duplicate and ensure that the other\n // requests are known and accounted for.\n mapping(bytes32 => uint256) public refundsRequested;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n // Note: this needs to be larger than the max transfer size to ensure that all slow fills are fillable, even if\n // their fees are negative.\n // It's important that it isn't too large, however, as it should be multipliable by ~2e18 without overflowing.\n // 1e40 * 2e18 = 2e58 << 2^255 ~= 5e76\n uint256 public constant SLOW_FILL_MAX_TOKENS_TO_SEND = 1e40;\n\n // Set max payout adjustment to something\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 indexed destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n event RefundRequested(\n address indexed relayer,\n address refundToken,\n uint256 amount,\n uint256 indexed originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n uint256 fillBlock,\n uint256 previousIdenticalRequests\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n /**\n * @notice Represents data used to fill a deposit.\n * @param relay Relay containing original data linked to deposit. Contains fields that can be\n * overridden by other parameters in the RelayExecution struct.\n * @param relayHash Hash of the relay data.\n * @param updatedRelayerFeePct Actual relayer fee pct to use for this relay.\n * @param updatedRecipient Actual recipient to use for this relay.\n * @param updatedMessage Actual message to use for this relay.\n * @param repaymentChainId Chain ID of the network that the relayer will receive refunds on.\n * @param maxTokensToSend Max number of tokens to pull from relayer.\n * @param maxCount Max count to protect the relayer from frontrunning.\n * @param slowFill Whether this is a slow fill.\n * @param payoutAdjustmentPct Adjustment to the payout amount. Can be used to increase or decrease the payout to\n * allow for rewards or penalties. Used in slow fills.\n */\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * @notice Packs together information to include in FilledRelay event.\n * @dev This struct is emitted as opposed to its constituent parameters due to the limit on number of\n * parameters in an event.\n * @param recipient Recipient of the relayed funds.\n * @param message Message included in the relay.\n * @param relayerFeePct Relayer fee pct used for this relay.\n * @param isSlowRelay Whether this is a slow relay.\n * @param payoutAdjustmentPct Adjustment to the payout amount.\n */\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects `deposit()` but not `speedUpDeposit()`, so that existing deposits can be sped up and still\n * relayed.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n /**\n * @notice Pauses fill-related functions. This is intended to be used if this contract is deprecated or when\n * something goes awry.\n * @dev Affects fillRelayWithUpdatedDeposit() and fillRelay().\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit FundsDeposited(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(SignedMath.abs(updatedRelayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpDeposit().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Caller signals to the system that they want a refund on this chain, which they set as the\n * `repaymentChainId` on the original fillRelay() call on the `destinationChainId`. An observer should be\n * be able to 1-to-1 match the emitted RefundRequested event with the FilledRelay event on the `destinationChainId`.\n * @dev This function could be used to artificially inflate the `fillCounter`, allowing the caller to \"frontrun\"\n * and cancel pending fills in the mempool. This would in the worst case censor fills at the cost of the caller's\n * gas costs. We don't view this as a major issue as the fill can be resubmitted and obtain the same incentive,\n * since incentives are based on validated refunds and would ignore these censoring attempts. This is no\n * different from calling `fillRelay` and setting msg.sender = recipient.\n * @dev Caller needs to pass in `fillBlock` that the FilledRelay event was emitted on the `destinationChainId`.\n * This is to make it hard to request a refund before a fill has been mined and to make lookups of the original\n * fill as simple as possible.\n * @param refundToken This chain's token equivalent for original fill destination token.\n * @param amount Original deposit amount.\n * @param originChainId Original origin chain ID.\n * @param destinationChainId Original destination chain ID.\n * @param realizedLpFeePct Original realized LP fee %.\n * @param depositId Original deposit ID.\n * @param maxCount Max count to protect the refund recipient from frontrunning.\n */\n function requestRefund(\n address refundToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n uint32 depositId,\n uint256 fillBlock,\n uint256 maxCount\n ) external nonReentrant {\n // Prevent unrealistic amounts from increasing fill counter too high.\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[refundToken] <= maxCount, \"Above max count\");\n\n // Track duplicate refund requests.\n bytes32 refundHash = keccak256(\n abi.encode(\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock\n )\n );\n\n // Track duplicate requests so that an offchain actor knows if an identical request has already been made.\n // If so, it can check to ensure that that request was thrown out as invalid before honoring the duplicate.\n // In particular, this is meant to handle odd cases where an initial request is invalidated based on\n // timing, but can be validated by a later, identical request.\n uint256 previousIdenticalRequests = refundsRequested[refundHash]++;\n\n // Refund will take tokens out of this pool, increment the fill counter. This function should only be\n // called if a relayer from destinationChainId wants to take a refund on this chain, a different chain.\n // This type of repayment should only be possible for full fills, so the starting fill amount should\n // always be 0. Also, just like in _fillRelay we should revert if the first fill pre fees rounds to 0,\n // and in this case `amount` == `fillAmountPreFees`.\n require(amount > 0, \"Amount must be > 0\");\n _updateCountFromFill(\n 0,\n true, // The refund is being requested here, so it is local.\n amount,\n realizedLpFeePct,\n refundToken,\n false // Slow fills should never match with a Refund. This should be enforced by off-chain bundle builders.\n );\n\n emit RefundRequested(\n // Set caller as relayer. If caller is not relayer from destination chain that originally sent\n // fill, then off-chain validator should discard this refund attempt.\n msg.sender,\n refundToken,\n amount,\n originChainId,\n destinationChainId,\n realizedLpFeePct,\n depositId,\n fillBlock,\n previousIdenticalRequests\n );\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: SLOW_FILL_MAX_TOKENS_TO_SEND,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n // This is equivalent to the amount to be sent by the relayer before fees have been taken out.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If fill amount minus fees, which is possible with small fill amounts and negative fees, then\n // revert.\n require(fillAmountPreFees > 0, \"fill amount pre fees is 0\");\n\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n }\n\n // Apply post-fees computation to amount that relayer will send to user. Rounding errors are possible\n // when computing fillAmountPreFees and then amountToSend, and we just want to enforce that\n // the error added to amountToSend is consistently applied to partial and full fills.\n uint256 amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n // This can only happen in a slow fill, where the contract is funding the relay.\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Allow the payout adjustment to go up to 1000% (i.e. 11x).\n // This is a sanity check to ensure the payouts do not grow too large via some sort of issue in bundle\n // construction.\n require(relayExecution.payoutAdjustmentPct <= 100e18, \"payoutAdjustmentPct too large\");\n\n // Note: since _computeAmountPostFees is typically intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n\n // Note: this error should never happen, since the maxTokensToSend is expected to be set much higher than\n // the amount, but it is here as a sanity check.\n require(amountToSend <= relayExecution.maxTokensToSend, \"Somehow hit maxTokensToSend!\");\n }\n\n // Since the first partial fill is used to update the fill counter for the entire refund amount, we don't have\n // a simple way to handle the case where follow-up partial fills take repayment on different chains. We'd\n // need a way to decrement the fill counter in this case (or increase deposit counter) to ensure that users\n // have adequate frontrunning protections.\n // Instead of adding complexity, we require that all partial fills set repayment chain equal to destination chain.\n // Note: .slowFill is checked because slow fills set repaymentChainId to 0.\n bool localRepayment = relayExecution.repaymentChainId == relayExecution.relay.destinationChainId;\n require(\n localRepayment || relayExecution.relay.amount == fillAmountPreFees || relayExecution.slowFill,\n \"invalid repayment chain\"\n );\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n localRepayment,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n bool localRepayment,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, a first partial fill with repayment on another chain, or a partial fill has already happened, do nothing, as these\n // should not impact the count. Initial 0-fills will not reach this part of the code.\n if (useContractFunds || startingFillAmount > 0 || !localRepayment) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/external/interfaces/WETH9Interface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Interface for the WETH9 contract.\n */\ninterface WETH9Interface {\n /**\n * @notice Burn Wrapped Ether and receive native Ether.\n * @param wad Amount of WETH to unwrap and send to caller.\n */\n function withdraw(uint256 wad) external;\n\n /**\n * @notice Lock native Ether and mint Wrapped Ether ERC20\n * @dev msg.value is amount of Wrapped Ether to mint/Ether to lock.\n */\n function deposit() external payable;\n\n /**\n * @notice Get balance of WETH held by `guy`.\n * @param guy Address to get balance of.\n * @return wad Amount of WETH held by `guy`.\n */\n function balanceOf(address guy) external view returns (uint256 wad);\n\n /**\n * @notice Transfer `wad` of WETH from caller to `guy`.\n * @param guy Address to send WETH to.\n * @param wad Amount of WETH to send.\n * @return ok True if transfer succeeded.\n */\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Interface for the WETH9 contract.\n */\ninterface WETH9Interface {\n /**\n * @notice Burn Wrapped Ether and receive native Ether.\n * @param wad Amount of WETH to unwrap and send to caller.\n */\n function withdraw(uint256 wad) external;\n\n /**\n * @notice Lock native Ether and mint Wrapped Ether ERC20\n * @dev msg.value is amount of Wrapped Ether to mint/Ether to lock.\n */\n function deposit() external payable;\n\n /**\n * @notice Get balance of WETH held by `guy`.\n * @param guy Address to get balance of.\n * @return wad Amount of WETH held by `guy`.\n */\n function balanceOf(address guy) external view returns (uint256 wad);\n\n /**\n * @notice Transfer `wad` of WETH from caller to `guy`.\n * @param guy Address to send WETH to.\n * @param wad Amount of WETH to send.\n * @return ok True if transfer succeeded.\n */\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" }, "contracts/upgradeable/MultiCallerUpgradeable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title MultiCallerUpgradeable\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title MultiCallerUpgradeable\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/upgradeable/EIP712CrossChainUpgradeable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure it's always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" @@ -167,58 +167,58 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, OwnableUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @dev crossDomainAdmin is unused on this contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __Ownable_init();\n __SpokePool_init(_initialDepositId, _hubPool, _hubPool, _wethAddress);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // The SpokePool deployed to the same network as the HubPool must be owned by the HubPool.\n // A core assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, OwnableUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @dev crossDomainAdmin is unused on this contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __Ownable_init();\n __SpokePool_init(_initialDepositId, _hubPool, _hubPool, _wethAddress);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // The SpokePool deployed to the same network as the HubPool must be owned by the HubPool.\n // A core assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20Upgradeable is IERC20Upgradeable {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9Interface public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9Interface _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n //slither-disable-next-line missing-zero-check\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n //slither-disable-next-line missing-zero-check\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20Upgradeable token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20Upgradeable token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n //slither-disable-next-line arbitrary-send-eth\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20Upgradeable is IERC20Upgradeable {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9Interface public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9Interface _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n //slither-disable-next-line missing-zero-check\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n //slither-disable-next-line missing-zero-check\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20Upgradeable token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20Upgradeable token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n //slither-disable-next-line arbitrary-send-eth\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ninterface LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ninterface LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice IFxMessageProcessor represents interface to process messages.\n */\ninterface IFxMessageProcessor {\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See comment for `_requireAdminSender` for more details.\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n */\n function initialize(\n uint32 _initialDepositId,\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild\n ) public initializer {\n callValidated = false;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wmaticAddress);\n polygonTokenBridger = _polygonTokenBridger;\n //slither-disable-next-line missing-zero-check\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n //slither-disable-next-line missing-zero-check\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n /// This is a safe delegatecall because its made to address(this) so there is no risk of delegating to a\n /// selfdestruct().\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(data);\n //slither-disable-end low-level-calls\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, rootMessageSender);\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Unlike other ERC20 transfers, Matic transfers from L1 -> L2 bridging don't result in an L2 call into\n * the contract receiving the tokens, so wrapping must be done via a separate transaction. In other words,\n * we can't rely upon a `fallback()` method being triggered to wrap MATIC upon receiving it.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n //slither-disable-next-line arbitrary-send-eth\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./interfaces/SpokePoolInterface.sol\";\n\n/**\n * @notice IFxMessageProcessor represents interface to process messages.\n */\ninterface IFxMessageProcessor {\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20Upgradeable for PolygonIERC20Upgradeable;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See comment for `_requireAdminSender` for more details.\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n */\n function initialize(\n uint32 _initialDepositId,\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild\n ) public initializer {\n callValidated = false;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wmaticAddress);\n polygonTokenBridger = _polygonTokenBridger;\n //slither-disable-next-line missing-zero-check\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n //slither-disable-next-line missing-zero-check\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n /// This is a safe delegatecall because its made to address(this) so there is no risk of delegating to a\n /// selfdestruct().\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(data);\n //slither-disable-end low-level-calls\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, rootMessageSender);\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Unlike other ERC20 transfers, Matic transfers from L1 -> L2 bridging don't result in an L2 call into\n * the contract receiving the tokens, so wrapping must be done via a separate transaction. In other words,\n * we can't rely upon a `fallback()` method being triggered to wrap MATIC upon receiving it.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20Upgradeable(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n //slither-disable-next-line arbitrary-send-eth\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9Interface public immutable l1Weth = WETH9Interface(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9Interface public immutable l1Weth = WETH9Interface(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n * This interface is implemented by an adapter contract that is deployed on L1.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n /**\n * @notice Send message to `target` on L2.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param target L2 address to send message to.\n * @param message Message to send to `target`.\n */\n function relayMessage(address target, bytes calldata message) external payable;\n\n /**\n * @notice Send `amount` of `l1Token` to `to` on L2. `l2Token` is the L2 address equivalent of `l1Token`.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param l1Token L1 token to bridge.\n * @param l2Token L2 token to receive.\n * @param amount Amount of `l1Token` to bridge.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n * This interface is implemented by an adapter contract that is deployed on L1.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n /**\n * @notice Send message to `target` on L2.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param target L2 address to send message to.\n * @param message Message to send to `target`.\n */\n function relayMessage(address target, bytes calldata message) external payable;\n\n /**\n * @notice Send `amount` of `l1Token` to `to` on L2. `l2Token` is the L2 address equivalent of `l1Token`.\n * @dev This method is marked payable because relaying the message might require a fee\n * to be paid by the sender to forward the message to L2. However, it will not send msg.value\n * to the target contract on L2.\n * @param l1Token L1 token to bridge.\n * @param l2Token L2 token to receive.\n * @param amount Amount of `l1Token` to bridge.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Succinct_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/SuccinctInterfaces.sol\";\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Succinct_Adapter is AdapterInterface {\n ITelepathyBroadcaster public immutable succinctSourceAmb;\n uint16 public immutable destinationChainId;\n\n // Special Succinct event for additional tracking information.\n event SuccinctMessageRelayed(bytes32 messageRoot, uint16 destinationChainId, address target, bytes message);\n\n /**\n * @notice Constructs new Adapter.\n * @param _succinctSourceAmb address of the SourceAmb succinct contract for sending messages.\n * @param _destinationChainId chainId of the destination.\n */\n constructor(ITelepathyBroadcaster _succinctSourceAmb, uint16 _destinationChainId) {\n succinctSourceAmb = _succinctSourceAmb;\n destinationChainId = _destinationChainId;\n }\n\n /**\n * @notice Send cross-chain message to target on the destination.\n * @param target Contract on the destination that will receive the message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n bytes32 messageRoot = succinctSourceAmb.send(destinationChainId, target, message);\n\n // Note: this emits two events. MessageRelayed for the sake of compatibility with other adapters.\n // It emits SuccinctMessageRelayed to encode additional tracking information that is Succinct-specific.\n emit MessageRelayed(target, message);\n emit SuccinctMessageRelayed(messageRoot, destinationChainId, target, message);\n }\n\n /**\n * @notice No-op relay tokens method.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n // This method is intentionally left as a no-op.\n // If the adapter is intended to be able to relay tokens, this method should be overriden.\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/SuccinctInterfaces.sol\";\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Succinct_Adapter is AdapterInterface {\n ITelepathyBroadcaster public immutable succinctSourceAmb;\n uint16 public immutable destinationChainId;\n\n // Special Succinct event for additional tracking information.\n event SuccinctMessageRelayed(bytes32 messageRoot, uint16 destinationChainId, address target, bytes message);\n\n /**\n * @notice Constructs new Adapter.\n * @param _succinctSourceAmb address of the SourceAmb succinct contract for sending messages.\n * @param _destinationChainId chainId of the destination.\n */\n constructor(ITelepathyBroadcaster _succinctSourceAmb, uint16 _destinationChainId) {\n succinctSourceAmb = _succinctSourceAmb;\n destinationChainId = _destinationChainId;\n }\n\n /**\n * @notice Send cross-chain message to target on the destination.\n * @param target Contract on the destination that will receive the message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n bytes32 messageRoot = succinctSourceAmb.send(destinationChainId, target, message);\n\n // Note: this emits two events. MessageRelayed for the sake of compatibility with other adapters.\n // It emits SuccinctMessageRelayed to encode additional tracking information that is Succinct-specific.\n emit MessageRelayed(target, message);\n emit SuccinctMessageRelayed(messageRoot, destinationChainId, target, message);\n }\n\n /**\n * @notice No-op relay tokens method.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n // This method is intentionally left as a no-op.\n // If the adapter is intended to be able to relay tokens, this method should be overriden.\n }\n}\n" }, "contracts/external/interfaces/SuccinctInterfaces.sol": { "content": "pragma solidity ^0.8.0;\n\n// These interfaces are a subset of the Succinct interfaces here: https://github.com/succinctlabs/telepathy-contracts.\n\n// This interface should be implemented by any contract wanting to receive messages sent over the Succinct bridge.\ninterface ITelepathyHandler {\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external returns (bytes4);\n}\n\n// This interface represents the contract that we call into to send messages over the Succinct AMB.\ninterface ITelepathyBroadcaster {\n function send(\n uint16 _recipientChainId,\n address _recipientAddress,\n bytes calldata _data\n ) external returns (bytes32);\n}\n" }, "contracts/Succinct_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./external/interfaces/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n event SetSuccinctTargetAmb(address indexed newSuccinctTargetAmb);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be\n // misinterpreted. Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the adminCallValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure adminCallValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset adminCallValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n emit SetSuccinctTargetAmb(_succinctTargetAmb);\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(msg.sender == succinctTargetAmb, \"caller not succinct AMB\");\n require(_senderAddress == hubPool, \"sender not hubPool\");\n require(_sourceChainId == hubChainId, \"source chain not hub chain\");\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, _senderAddress);\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\nimport \"./external/interfaces/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n event SetSuccinctTargetAmb(address indexed newSuccinctTargetAmb);\n event ReceivedMessageFromL1(address indexed caller, address indexed rootMessageSender);\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be\n // misinterpreted. Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the adminCallValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure adminCallValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset adminCallValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n emit SetSuccinctTargetAmb(_succinctTargetAmb);\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(msg.sender == succinctTargetAmb, \"caller not succinct AMB\");\n require(_senderAddress == hubPool, \"sender not hubPool\");\n require(_sourceChainId == hubChainId, \"source chain not hub chain\");\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n\n emit ReceivedMessageFromL1(msg.sender, _senderAddress);\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Send tokens to Polygon.\n */\ninterface IRootChainManager {\n /**\n * @notice Send msg.value of ETH to Polygon\n * @param user Recipient of ETH on Polygon.\n */\n function depositEtherFor(address user) external payable;\n\n /**\n * @notice Send ERC20 tokens to Polygon.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param rootToken L1 Address of token to send.\n * @param depositData Data to pass to L2 including amount of tokens to send. Should be abi.encode(amount).\n */\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\n/**\n * @notice Send arbitrary messages to Polygon.\n */\ninterface IFxStateSender {\n /**\n * @notice Send arbitrary message to Polygon.\n * @param _receiver Address on Polygon to receive message.\n * @param _data Message to send to `_receiver` on Polygon.\n */\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Similar to RootChainManager, but for Matic (Plasma) bridge.\n */\ninterface DepositManager {\n /**\n * @notice Send tokens to Polygon. Only used to send MATIC in this Polygon_Adapter.\n * @param token L1 token to send. Should be MATIC.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param amount Amount of `token` to send.\n */\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9Interface public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9Interface _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Send tokens to Polygon.\n */\ninterface IRootChainManager {\n /**\n * @notice Send msg.value of ETH to Polygon\n * @param user Recipient of ETH on Polygon.\n */\n function depositEtherFor(address user) external payable;\n\n /**\n * @notice Send ERC20 tokens to Polygon.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param rootToken L1 Address of token to send.\n * @param depositData Data to pass to L2 including amount of tokens to send. Should be abi.encode(amount).\n */\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\n/**\n * @notice Send arbitrary messages to Polygon.\n */\ninterface IFxStateSender {\n /**\n * @notice Send arbitrary message to Polygon.\n * @param _receiver Address on Polygon to receive message.\n * @param _data Message to send to `_receiver` on Polygon.\n */\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Similar to RootChainManager, but for Matic (Plasma) bridge.\n */\ninterface DepositManager {\n /**\n * @notice Send tokens to Polygon. Only used to send MATIC in this Polygon_Adapter.\n * @param token L1 token to send. Should be MATIC.\n * @param user Recipient of L2 equivalent tokens on Polygon.\n * @param amount Amount of `token` to send.\n */\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9Interface public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9Interface _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Synthetix custom bridge to Optimism.\n */\ninterface SynthetixBridgeToOptimism is IL1StandardBridge {\n /**\n * @notice Send tokens to Optimism.\n * @param to Address to send tokens to on L2.\n * @param amount Amount of tokens to send.\n */\n function depositTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore it's only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0x39Ea01a0298C315d149a490E34B59Dbf2EC7e48F;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n address bridgeToUse = address(l1StandardBridge);\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) bridgeToUse = daiOptimismBridge; // 1. DAI\n if (l1Token == snx) bridgeToUse = snxOptimismBridge; // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(bridgeToUse, amount);\n if (l1Token == snx) SynthetixBridgeToOptimism(bridgeToUse).depositTo(to, amount);\n else IL1StandardBridge(bridgeToUse).depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Synthetix custom bridge to Optimism.\n */\ninterface SynthetixBridgeToOptimism is IL1StandardBridge {\n /**\n * @notice Send tokens to Optimism.\n * @param to Address to send tokens to on L2.\n * @param amount Amount of tokens to send.\n */\n function depositTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore it's only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0x39Ea01a0298C315d149a490E34B59Dbf2EC7e48F;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n address bridgeToUse = address(l1StandardBridge);\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) bridgeToUse = daiOptimismBridge; // 1. DAI\n if (l1Token == snx) bridgeToUse = snxOptimismBridge; // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(bridgeToUse, amount);\n if (l1Token == snx) SynthetixBridgeToOptimism(bridgeToUse).depositTo(to, amount);\n else IL1StandardBridge(bridgeToUse).depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -233,28 +233,28 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"../external/interfaces/WETH9Interface.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9Interface public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9Interface _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Arbitrum's L1 Inbox contract used to send messages to Arbitrum.\n */\ninterface ArbitrumL1InboxLike {\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @dev Caller must set msg.value equal to at least `maxSubmissionCost + maxGas * gasPriceBid`.\n * all msg.value will deposited to callValueRefundAddress on L2\n * @dev More details can be found here: https://developer.arbitrum.io/arbos/l1-to-l2-messaging\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function createRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed\n * funds come from the deposit alone, rather than falling back on the user's L2 balance\n * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).\n * createRetryableTicket method is the recommended standard.\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function unsafeCreateRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\n/**\n * @notice Layer 1 Gateway contract for bridging standard ERC20s to Arbitrum.\n */\ninterface ArbitrumL1ERC20GatewayLike {\n /**\n * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges\n * like the DAI bridge.\n * @dev Refunded to aliased L2 address of sender if sender has code on L1, otherwise to to sender's EOA on L2.\n * @param _l1Token L1 address of ERC20\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice Deposit ERC20 token from Ethereum into Arbitrum.\n * @dev L2 address alias will not be applied to the following types of addresses on L1:\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * @param _l1Token L1 address of ERC20\n * @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransferCustomRefund(\n address _l1Token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice get ERC20 gateway for token.\n * @param _token ERC20 address.\n * @return address of ERC20 gateway.\n */\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Interface for Arbitrum's L1 Inbox contract used to send messages to Arbitrum.\n */\ninterface ArbitrumL1InboxLike {\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @dev Caller must set msg.value equal to at least `maxSubmissionCost + maxGas * gasPriceBid`.\n * all msg.value will deposited to callValueRefundAddress on L2\n * @dev More details can be found here: https://developer.arbitrum.io/arbos/l1-to-l2-messaging\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function createRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n\n /**\n * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts\n * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed\n * funds come from the deposit alone, rather than falling back on the user's L2 balance\n * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).\n * createRetryableTicket method is the recommended standard.\n * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)\n * @param data ABI encoded data of L2 message\n * @return unique message number of the retryable transaction\n */\n function unsafeCreateRetryableTicket(\n address to,\n uint256 l2CallValue,\n uint256 maxSubmissionCost,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n uint256 gasLimit,\n uint256 maxFeePerGas,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\n/**\n * @notice Layer 1 Gateway contract for bridging standard ERC20s to Arbitrum.\n */\ninterface ArbitrumL1ERC20GatewayLike {\n /**\n * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges\n * like the DAI bridge.\n * @dev Refunded to aliased L2 address of sender if sender has code on L1, otherwise to to sender's EOA on L2.\n * @param _l1Token L1 address of ERC20\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice Deposit ERC20 token from Ethereum into Arbitrum.\n * @dev L2 address alias will not be applied to the following types of addresses on L1:\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * @param _l1Token L1 address of ERC20\n * @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2\n * @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract),\n * not subject to L2 aliasing. This account, or its L2 alias if it have code in L1, will also be able to\n * cancel the retryable ticket and receive callvalue refund\n * @param _amount Token Amount\n * @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution\n * @param _gasPriceBid Gas price for L2 execution\n * @param _data encoded data from router and user\n * @return res abi encoded inbox sequence number\n */\n function outboundTransferCustomRefund(\n address _l1Token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n /**\n * @notice get ERC20 gateway for token.\n * @param _token ERC20 address.\n * @return address of ERC20 gateway.\n */\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.unsafeCreateRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.unsafeCreateRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n// https://github.com/Synthetixio/synthetix/blob/5ca27785fad8237fb0710eac01421cafbbd69647/contracts/SynthetixBridgeToBase.sol#L50\ninterface SynthetixBridgeToBase {\n function withdrawTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas;\n\n // ETH is an ERC20 on OVM.\n address public l2Eth;\n\n // Address of the Optimism L2 messenger.\n address public messenger;\n\n // Address of custom bridge used to bridge Synthetix-related assets like SNX.\n address private constant SYNTHETIX_BRIDGE = 0x136b1EC699c62b0606854056f02dC7Bb80482d63;\n\n // Address of SNX ERC20\n address private constant SNX = 0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n */\n function __OvmSpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken\n ) public onlyInitializing {\n l1Gas = 5_000_000;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER;\n //slither-disable-next-line missing-zero-check\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n //slither-disable-next-line arbitrary-send-eth\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9Interface(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n // Handle custom SNX bridge which doesn't conform to the standard bridge interface.\n if (relayerRefundLeaf.l2TokenAddress == SNX)\n SynthetixBridgeToBase(SYNTHETIX_BRIDGE).withdrawTo(\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn // _amount.\n );\n else\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal view override {\n require(\n LibOptimismUpgradeable.crossChainSender(messenger) == crossDomainAdmin,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./external/interfaces/WETH9Interface.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n// https://github.com/Synthetixio/synthetix/blob/5ca27785fad8237fb0710eac01421cafbbd69647/contracts/SynthetixBridgeToBase.sol#L50\ninterface SynthetixBridgeToBase {\n function withdrawTo(address to, uint256 amount) external;\n}\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas;\n\n // ETH is an ERC20 on OVM.\n address public l2Eth;\n\n // Address of the Optimism L2 messenger.\n address public messenger;\n\n // Address of custom bridge used to bridge Synthetix-related assets like SNX.\n address private constant SYNTHETIX_BRIDGE = 0x136b1EC699c62b0606854056f02dC7Bb80482d63;\n\n // Address of SNX ERC20\n address private constant SNX = 0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n */\n function __OvmSpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken\n ) public onlyInitializing {\n l1Gas = 5_000_000;\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER;\n //slither-disable-next-line missing-zero-check\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n //slither-disable-next-line arbitrary-send-eth\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9Interface(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n // Handle custom SNX bridge which doesn't conform to the standard bridge interface.\n if (relayerRefundLeaf.l2TokenAddress == SNX)\n SynthetixBridgeToBase(SYNTHETIX_BRIDGE).withdrawTo(\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn // _amount.\n );\n else\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal view override {\n require(\n LibOptimismUpgradeable.crossChainSender(messenger) == crossDomainAdmin,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/crosschain/optimism/LibOptimismUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/LibOptimism.sol)\n\npragma solidity ^0.8.4;\n\nimport { ICrossDomainMessengerUpgradeable as Optimism_Bridge } from \"../../vendor/optimism/ICrossDomainMessengerUpgradeable.sol\";\nimport \"../errorsUpgradeable.sol\";\n\n/**\n * @dev Primitives for cross-chain aware contracts for https://www.optimism.io/[Optimism].\n * See the https://community.optimism.io/docs/developers/bridge/messaging/#accessing-msg-sender[documentation]\n * for the functionality used here.\n */\nlibrary LibOptimismUpgradeable {\n /**\n * @dev Returns whether the current function call is the result of a\n * cross-chain message relayed by `messenger`.\n */\n function isCrossChain(address messenger) internal view returns (bool) {\n return msg.sender == messenger;\n }\n\n /**\n * @dev Returns the address of the sender that triggered the current\n * cross-chain message through `messenger`.\n *\n * NOTE: {isCrossChain} should be checked before trying to recover the\n * sender, as it will revert with `NotCrossChainCall` if the current\n * function call is not the result of a cross-chain message.\n */\n function crossChainSender(address messenger) internal view returns (address) {\n if (!isCrossChain(messenger)) revert NotCrossChainCall();\n\n return Optimism_Bridge(messenger).xDomainMessageSender();\n }\n}\n" @@ -272,31 +272,31 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (vendor/optimism/ICrossDomainMessenger.sol)\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessengerUpgradeable {\n /**********\n * Events *\n **********/\n\n event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit);\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/test/AcrossMessageHandlerMock.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\n\ncontract AcrossMessageHandlerMock is AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external override {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\n\ncontract AcrossMessageHandlerMock is AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external override {}\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n //slither-disable-next-line unused-return\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n */\n function initialize(\n uint32 _initialDepositId,\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress);\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n //slither-disable-next-line unused-return\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -305,28 +305,28 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "contracts/test/ArbitrumMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ncontract ArbitrumMockErc20GatewayRouter {\n function outboundTransferCustomRefund(\n address,\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function outboundTransfer(\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function getGateway(address) external view returns (address) {\n return address(this);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ncontract ArbitrumMockErc20GatewayRouter {\n function outboundTransferCustomRefund(\n address,\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function outboundTransfer(\n address,\n address,\n uint256,\n uint256,\n uint256,\n bytes calldata _data\n ) external payable returns (bytes memory) {\n return _data;\n }\n\n function getGateway(address) external view returns (address) {\n return address(this);\n }\n}\n" }, "contracts/test/SuccinctMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ncontract TelepathyBroadcasterMock {\n function send(\n uint16,\n address,\n bytes calldata\n ) external pure returns (bytes32) {\n return bytes32(0);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ncontract TelepathyBroadcasterMock {\n function send(\n uint16,\n address,\n bytes calldata\n ) external pure returns (bytes32) {\n return bytes32(0);\n }\n}\n" } }, "settings": { diff --git a/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json b/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json index e20202ac..633034a1 100644 --- a/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json +++ b/deployments/goerli/solcInputs/f5a0c3a42678b8be065d2d7cfda0e784.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/merkle-distributor/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is Ownable {\n using SafeERC20 for IERC20;\n\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) external {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n merkleWindows[_claim.windowIndex].remainingAmount -= batchedAmount;\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) external {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is Ownable {\n using SafeERC20 for IERC20;\n\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) external {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n merkleWindows[_claim.windowIndex].remainingAmount -= batchedAmount;\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) external {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) private {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,73 +32,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -113,13 +113,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -128,58 +128,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -188,22 +188,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/kovan/AcrossConfigStore.json b/deployments/kovan/AcrossConfigStore.json index a2ba3695..3d105e8e 100644 --- a/deployments/kovan/AcrossConfigStore.json +++ b/deployments/kovan/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f838061007e6000396000f3fe60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Ethereum_Adapter.json b/deployments/kovan/Ethereum_Adapter.json index 5c0305db..2347ba83 100644 --- a/deployments/kovan/Ethereum_Adapter.json +++ b/deployments/kovan/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Ethereum_SpokePool.json b/deployments/kovan/Ethereum_SpokePool.json index 7565d55b..9b35e1e5 100644 --- a/deployments/kovan/Ethereum_SpokePool.json +++ b/deployments/kovan/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200466b3803806200466b8339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b608051614382620002e9600039600081816101d901528181610ce601528181610daf0152818161234d01528181612bd30152612c2901526143826000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/LpTokenFactory.json b/deployments/kovan/LpTokenFactory.json index cb3685b8..3e71a0aa 100644 --- a/deployments/kovan/LpTokenFactory.json +++ b/deployments/kovan/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/Optimism_Adapter.json b/deployments/kovan/Optimism_Adapter.json index 9bc90b13..428bab46 100644 --- a/deployments/kovan/Optimism_Adapter.json +++ b/deployments/kovan/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052621e848060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161113538038061113583398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f606101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108ca0152610f606000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "devdoc": { diff --git a/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index a0cc1d52..2a6425e5 100644 --- a/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json b/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json index 52e7ecd2..08c3cc5c 100644 --- a/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json +++ b/deployments/kovan/solcInputs/f654478e897007c7ba14581b070ec005.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/mainnet/AcrossConfigStore.json b/deployments/mainnet/AcrossConfigStore.json index 451c31c5..8d3dd3ad 100644 --- a/deployments/mainnet/AcrossConfigStore.json +++ b/deployments/mainnet/AcrossConfigStore.json @@ -219,7 +219,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedGlobalConfig\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"key\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"UpdatedTokenConfig\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"globalConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenConfig\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateGlobalConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"updateTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract should not perform any validation on the setting values and should be owned by the governance system of the full contract suite..\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateGlobalConfig(bytes32,string)\":{\"params\":{\"key\":\"Key to update.\",\"value\":\"Value to update.\"}},\"updateTokenConfig(address,string)\":{\"params\":{\"l1Token\":\"the l1 token address to update value for.\",\"value\":\"Value to update.\"}}},\"title\":\"Allows admin to set and update configuration settings for full contract system. These settings are designed to be consumed by off-chain bots, rather than by other contracts.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateGlobalConfig(bytes32,string)\":{\"notice\":\"Updates global config.\"},\"updateTokenConfig(address,string)\":{\"notice\":\"Updates token config.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AcrossConfigStore.sol\":\"AcrossConfigStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/AcrossConfigStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\\r\\n * to be consumed by off-chain bots, rather than by other contracts.\\r\\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\\r\\n * system of the full contract suite..\\r\\n */\\r\\ncontract AcrossConfigStore is Ownable, MultiCaller {\\r\\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\\r\\n // Transfer Thresholds.\\r\\n mapping(address => string) public l1TokenConfig;\\r\\n\\r\\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\\r\\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\\r\\n mapping(bytes32 => string) public globalConfig;\\r\\n\\r\\n event UpdatedTokenConfig(address indexed key, string value);\\r\\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\\r\\n\\r\\n /**\\r\\n * @notice Updates token config.\\r\\n * @param l1Token the l1 token address to update value for.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\\r\\n l1TokenConfig[l1Token] = value;\\r\\n emit UpdatedTokenConfig(l1Token, value);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Updates global config.\\r\\n * @param key Key to update.\\r\\n * @param value Value to update.\\r\\n */\\r\\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\\r\\n globalConfig[key] = value;\\r\\n emit UpdatedGlobalConfig(key, value);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x50e795f25b10c12ab45a9db5c0bf44d56a720710bde31bf4a879a84f0f9d9b3a\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f838061007e6000396000f3fe60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c80639fdd403a1161004e5780639fdd403a14610122578063ac9650d814610142578063e5e818ae14610162578063f2fde38b1461018257600080fd5b806350fbbd0114610080578063715018a6146100b65780638098b875146100cd5780638da5cb5b146100ed575b600080fd5b34801561008c57600080fd5b506100a061009b36600461099e565b6101a2565b6040516100ad9190610a3a565b60405180910390f35b3480156100c257600080fd5b506100cb61023c565b005b3480156100d957600080fd5b506100cb6100e8366004610b11565b6102ce565b3480156100f957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ad565b34801561012e57600080fd5b506100a061013d366004610ba2565b6103d8565b610155610150366004610bbb565b6103f1565b6040516100ad9190610c30565b34801561016e57600080fd5b506100cb61017d366004610cb0565b6105cb565b34801561018e57600080fd5b506100cb61019d36600461099e565b6106a5565b600160205260009081526040902080546101bb90610d2c565b80601f01602080910402602001604051908101604052809291908181526020018280546101e790610d2c565b80156102345780601f1061020957610100808354040283529160200191610234565b820191906000526020600020905b81548152906001019060200180831161021757829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102cc60006107d5565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020908152604090912082516103859284019061084a565b508173ffffffffffffffffffffffffffffffffffffffff167f2170feb790d9bf809ba50947096322ec651593149b6f78e673e51c1c67cfe3fd826040516103cc9190610a3a565b60405180910390a25050565b600260205260009081526040902080546101bb90610d2c565b6060341561045b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016102b9565b8167ffffffffffffffff81111561047457610474610a4d565b6040519080825280602002602001820160405280156104a757816020015b60608152602001906001900390816104925790505b50905060005b828110156105c457600080308686858181106104cb576104cb610d7f565b90506020028101906104dd9190610dae565b6040516104eb929190610e1a565b600060405180830381855af49150503d8060008114610526576040519150601f19603f3d011682016040523d82523d6000602084013e61052b565b606091505b5091509150816105915760448151101561054457600080fd5b6004810190508080602001905181019061055e9190610e2a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b99190610a3a565b808484815181106105a4576105a4610d7f565b6020026020010181905250505080806105bc90610ea1565b9150506104ad565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461064c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b60008381526002602052604090206106659083836108ce565b50827f84c11a81ce8e8060e814e03c4606fe325e7a24ecc22ef7001254e27de3762f498383604051610698929190610f00565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff81166107c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6107d2816107d5565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461085690610d2c565b90600052602060002090601f01602090048101928261087857600085556108be565b82601f1061089157805160ff19168380011785556108be565b828001600101855582156108be579182015b828111156108be5782518255916020019190600101906108a3565b506108ca929150610960565b5090565b8280546108da90610d2c565b90600052602060002090601f0160209004810192826108fc57600085556108be565b82601f10610933578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556108be565b828001600101855582156108be579182015b828111156108be578235825591602001919060010190610945565b5b808211156108ca5760008155600101610961565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099957600080fd5b919050565b6000602082840312156109b057600080fd5b6109b982610975565b9392505050565b60005b838110156109db5781810151838201526020016109c3565b838111156109ea576000848401525b50505050565b60008151808452610a088160208601602086016109c0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109b960208301846109f0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ac357610ac3610a4d565b604052919050565b600067ffffffffffffffff821115610ae557610ae5610a4d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610b2457600080fd5b610b2d83610975565b9150602083013567ffffffffffffffff811115610b4957600080fd5b8301601f81018513610b5a57600080fd5b8035610b6d610b6882610acb565b610a7c565b818152866020838501011115610b8257600080fd5b816020840160208301376000602083830101528093505050509250929050565b600060208284031215610bb457600080fd5b5035919050565b60008060208385031215610bce57600080fd5b823567ffffffffffffffff80821115610be657600080fd5b818501915085601f830112610bfa57600080fd5b813581811115610c0957600080fd5b8660208260051b8501011115610c1e57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610ca3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610c918583516109f0565b94509285019290850190600101610c57565b5092979650505050505050565b600080600060408486031215610cc557600080fd5b83359250602084013567ffffffffffffffff80821115610ce457600080fd5b818601915086601f830112610cf857600080fd5b813581811115610d0757600080fd5b876020828501011115610d1957600080fd5b6020830194508093505050509250925092565b600181811c90821680610d4057607f821691505b602082108103610d79577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610de357600080fd5b83018035915067ffffffffffffffff821115610dfe57600080fd5b602001915036819003821315610e1357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610e3c57600080fd5b815167ffffffffffffffff811115610e5357600080fd5b8201601f81018413610e6457600080fd5b8051610e72610b6882610acb565b818152856020838501011115610e8757600080fd5b610e988260208301602086016109c0565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610ef9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220d3e5f95ca858b01395b7b124c7fd69c798a7d6384c1232fea5581bad2ff8b29a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_Adapter.json b/deployments/mainnet/Arbitrum_Adapter.json index 681870f0..7e0a3f8b 100644 --- a/deployments/mainnet/Arbitrum_Adapter.json +++ b/deployments/mainnet/Arbitrum_Adapter.json @@ -243,7 +243,7 @@ "args": ["0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef"], "numDeployments": 1, "solcInputHash": "aa94850b4a0bee17111a41299cfa0033", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_MESSAGE_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"l2GasLimit\",\"type\":\"uint32\"}],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue(uint32)\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue(uint32)\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x09fa3131b8c17515dc85595521fc23524b1c5897a494ae33c4a30b525bf0e4fe\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_MESSAGE_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"l2GasLimit\",\"type\":\"uint32\"}],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue(uint32)\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue(uint32)\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x09fa3131b8c17515dc85595521fc23524b1c5897a494ae33c4a30b525bf0e4fe\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405234801561001057600080fd5b5060405161128338038061128383398101604081905261002f9161005e565b6001600160a01b039182166080521660a052610098565b6001600160a01b038116811461005b57600080fd5b50565b6000806040838503121561007157600080fd5b825161007c81610046565b602084015190925061008d81610046565b809150509250929050565b60805160a0516111ab6100d86000396000818160c8015281816102c40152818161041b015261050c015260008181610195015261064c01526111ab6000f3fe6080604052600436106100b15760003560e01c80639ae3668511610069578063c735281e1161004e578063c735281e146101f8578063e599477e1461020f578063e6eb8ade1461022a57600080fd5b80639ae36685146101b75780639c3ba200146101d057600080fd5b806328f2716e1161009a57806328f2716e1461014257806352c8c75c1461016e5780638134f3851461018357600080fd5b80631ba4a9cb146100b65780631fc1ba7614610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610c27565b61023d565b60405190815260200161010b565b34801561014e57600080fd5b50610159620493e081565b60405163ffffffff909116815260200161010b565b61018161017c366004610c72565b61026b565b005b34801561018f57600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061013464012a05f20081565b3480156101dc57600080fd5b506100ea73428ab2ba90eba0a4be7af34c9ac451ab061ac01081565b34801561020457600080fd5b50610159621e848081565b34801561021b57600080fd5b50610134662386f26fc1000081565b610181610238366004610d89565b61063a565b600061025463ffffffff831664012a05f200610e4b565b61026590662386f26fc10000610e88565b92915050565b6000610279620493e0610758565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561030b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032f9190610ea0565b905061035273ffffffffffffffffffffffffffffffffffffffff871682866107d9565b6000662386f26fc1000060405160200161037d91815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905073ffffffffffffffffffffffffffffffffffffffff8716736b175474e89094c44da98b954eedeac495271d0f036104cf576040517fd2ce7d6500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d65908590610464908b9089908b90620493e09064012a05f200908a90600401610f33565b60006040518083038185885af1158015610482573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c99190810190610f90565b506105d2565b6040517f4fb1a07b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634fb1a07b90859061056b908b9073428ab2ba90eba0a4be7af34c9ac451ab061ac010908a908c90620493e09064012a05f200908b90600401611007565b60006040518083038185885af1158015610589573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105d09190810190610f90565b505b6040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b6000610648621e8480610758565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded82856000662386f26fc1000073428ab2ba90eba0a4be7af34c9ac451ab061ac01080621e848064012a05f2008b6040518a63ffffffff1660e01b81526004016106d698979695949392919061106d565b60206040518083038185885af11580156106f4573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061071991906110dc565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4838360405161074b9291906110f5565b60405180910390a1505050565b60006107638261023d565b9050804710156107d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b919050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087491906110dc565b61087e9190610e88565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090e908590610914565b50505050565b6000610976826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a259092919063ffffffff16565b805190915015610a2057808060200190518101906109949190611124565b610a20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107cb565b505050565b6060610a348484600085610a3e565b90505b9392505050565b606082471015610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107cb565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b779190611146565b60006040518083038185875af1925050503d8060008114610bb4576040519150601f19603f3d011682016040523d82523d6000602084013e610bb9565b606091505b5091509150610bc9828286610bd4565b979650505050505050565b60608315610be3575081610a37565b825115610bf35782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107cb9190611162565b600060208284031215610c3957600080fd5b813563ffffffff81168114610a3757600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c6f57600080fd5b50565b60008060008060808587031215610c8857600080fd5b8435610c9381610c4d565b93506020850135610ca381610c4d565b9250604085013591506060850135610cba81610c4d565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3b57610d3b610cc5565b604052919050565b600067ffffffffffffffff821115610d5d57610d5d610cc5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d9c57600080fd5b8235610da781610c4d565b9150602083013567ffffffffffffffff811115610dc357600080fd5b8301601f81018513610dd457600080fd5b8035610de7610de282610d43565b610cf4565b818152866020838501011115610dfc57600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e8357610e83610e1c565b500290565b60008219821115610e9b57610e9b610e1c565b500190565b600060208284031215610eb257600080fd5b8151610a3781610c4d565b60005b83811015610ed8578181015183820152602001610ec0565b8381111561090e5750506000910152565b60008151808452610f01816020860160208601610ebd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f8460c0830184610ee9565b98975050505050505050565b600060208284031215610fa257600080fd5b815167ffffffffffffffff811115610fb957600080fd5b8201601f81018413610fca57600080fd5b8051610fd8610de282610d43565b818152856020838501011115610fed57600080fd5b610ffe826020830160208601610ebd565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff851660808301528360a083015260e060c083015261106060e0830184610ee9565b9998505050505050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e08401526110cd81840185610ee9565b9b9a5050505050505050505050565b6000602082840312156110ee57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a346040830184610ee9565b60006020828403121561113657600080fd5b81518015158114610a3757600080fd5b60008251611158818460208701610ebd565b9190910192915050565b602081526000610a376020830184610ee956fea2646970667358221220b1f5489e25d9caa366e02e9f1600d99235c2ecffa1dee5130a86e9d1a2b8130064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c80639ae3668511610069578063c735281e1161004e578063c735281e146101f8578063e599477e1461020f578063e6eb8ade1461022a57600080fd5b80639ae36685146101b75780639c3ba200146101d057600080fd5b806328f2716e1161009a57806328f2716e1461014257806352c8c75c1461016e5780638134f3851461018357600080fd5b80631ba4a9cb146100b65780631fc1ba7614610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610c27565b61023d565b60405190815260200161010b565b34801561014e57600080fd5b50610159620493e081565b60405163ffffffff909116815260200161010b565b61018161017c366004610c72565b61026b565b005b34801561018f57600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061013464012a05f20081565b3480156101dc57600080fd5b506100ea73428ab2ba90eba0a4be7af34c9ac451ab061ac01081565b34801561020457600080fd5b50610159621e848081565b34801561021b57600080fd5b50610134662386f26fc1000081565b610181610238366004610d89565b61063a565b600061025463ffffffff831664012a05f200610e4b565b61026590662386f26fc10000610e88565b92915050565b6000610279620493e0610758565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561030b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032f9190610ea0565b905061035273ffffffffffffffffffffffffffffffffffffffff871682866107d9565b6000662386f26fc1000060405160200161037d91815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905073ffffffffffffffffffffffffffffffffffffffff8716736b175474e89094c44da98b954eedeac495271d0f036104cf576040517fd2ce7d6500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d65908590610464908b9089908b90620493e09064012a05f200908a90600401610f33565b60006040518083038185885af1158015610482573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c99190810190610f90565b506105d2565b6040517f4fb1a07b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634fb1a07b90859061056b908b9073428ab2ba90eba0a4be7af34c9ac451ab061ac010908a908c90620493e09064012a05f200908b90600401611007565b60006040518083038185885af1158015610589573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105d09190810190610f90565b505b6040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b6000610648621e8480610758565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded82856000662386f26fc1000073428ab2ba90eba0a4be7af34c9ac451ab061ac01080621e848064012a05f2008b6040518a63ffffffff1660e01b81526004016106d698979695949392919061106d565b60206040518083038185885af11580156106f4573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061071991906110dc565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac4838360405161074b9291906110f5565b60405180910390a1505050565b60006107638261023d565b9050804710156107d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b919050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087491906110dc565b61087e9190610e88565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090e908590610914565b50505050565b6000610976826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a259092919063ffffffff16565b805190915015610a2057808060200190518101906109949190611124565b610a20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107cb565b505050565b6060610a348484600085610a3e565b90505b9392505050565b606082471015610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107cb565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b779190611146565b60006040518083038185875af1925050503d8060008114610bb4576040519150601f19603f3d011682016040523d82523d6000602084013e610bb9565b606091505b5091509150610bc9828286610bd4565b979650505050505050565b60608315610be3575081610a37565b825115610bf35782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107cb9190611162565b600060208284031215610c3957600080fd5b813563ffffffff81168114610a3757600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c6f57600080fd5b50565b60008060008060808587031215610c8857600080fd5b8435610c9381610c4d565b93506020850135610ca381610c4d565b9250604085013591506060850135610cba81610c4d565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3b57610d3b610cc5565b604052919050565b600067ffffffffffffffff821115610d5d57610d5d610cc5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d9c57600080fd5b8235610da781610c4d565b9150602083013567ffffffffffffffff811115610dc357600080fd5b8301601f81018513610dd457600080fd5b8035610de7610de282610d43565b610cf4565b818152866020838501011115610dfc57600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e8357610e83610e1c565b500290565b60008219821115610e9b57610e9b610e1c565b500190565b600060208284031215610eb257600080fd5b8151610a3781610c4d565b60005b83811015610ed8578181015183820152602001610ec0565b8381111561090e5750506000910152565b60008151808452610f01816020860160208601610ebd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f8460c0830184610ee9565b98975050505050505050565b600060208284031215610fa257600080fd5b815167ffffffffffffffff811115610fb957600080fd5b8201601f81018413610fca57600080fd5b8051610fd8610de282610d43565b818152856020838501011115610fed57600080fd5b610ffe826020830160208601610ebd565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff851660808301528360a083015260e060c083015261106060e0830184610ee9565b9998505050505050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e08401526110cd81840185610ee9565b9b9a5050505050505050505050565b6000602082840312156110ee57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a346040830184610ee9565b60006020828403121561113657600080fd5b81518015158114610a3757600080fd5b60008251611158818460208701610ebd565b9190910192915050565b602081526000610a376020830184610ee956fea2646970667358221220b1f5489e25d9caa366e02e9f1600d99235c2ecffa1dee5130a86e9d1a2b8130064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_RescueAdapter.json b/deployments/mainnet/Arbitrum_RescueAdapter.json index fc1b3214..de2de3b5 100644 --- a/deployments/mainnet/Arbitrum_RescueAdapter.json +++ b/deployments/mainnet/Arbitrum_RescueAdapter.json @@ -219,7 +219,7 @@ "args": ["0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f"], "numDeployments": 1, "solcInputHash": "9ecc79ca0809d14763bad8554b06546b", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"aliasedL2HubPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to aliased hub pool.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to aliased hub pool address on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send transactions as if called by the aliased HubPool address.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":\"Arbitrum_RescueAdapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n function createRetryableTicketNoRefundAliasRewrite(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1273df00da12b4eb144cbfd15b32a2353a46cfd66f3440074f782a17084bf53d\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"./Arbitrum_Adapter.sol\\\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\\n * transactions as if called by the aliased HubPool address.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_RescueAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\\n l1Inbox = _l1ArbitrumInbox;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param message Data to send to aliased hub pool.\\n */\\n function relayMessage(address, bytes memory message) external payable override {\\n uint256 valueToReturn = abi.decode(message, (uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\\n l2RefundL2Address, // destAddr destination L2 contract address\\n valueToReturn, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n \\\"\\\" // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(aliasedL2HubPoolAddress, \\\"\\\");\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"useless function\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x28e520a2456ac047fca4e21aed8d0ce0a4d731941922a83ab56ec12543681f19\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"aliasedL2HubPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to aliased hub pool.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to aliased hub pool address on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send transactions as if called by the aliased HubPool address.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":\"Arbitrum_RescueAdapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n function createRetryableTicketNoRefundAliasRewrite(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter\\n // (i.e. the Arbitrum_RescueAdapter).\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n l2GasLimit,\\n l2GasPrice,\\n data\\n );\\n }\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1273df00da12b4eb144cbfd15b32a2353a46cfd66f3440074f782a17084bf53d\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_RescueAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"./Arbitrum_Adapter.sol\\\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\\n * transactions as if called by the aliased HubPool address.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_RescueAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\\n l1Inbox = _l1ArbitrumInbox;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param message Data to send to aliased hub pool.\\n */\\n function relayMessage(address, bytes memory message) external payable override {\\n uint256 valueToReturn = abi.decode(message, (uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\\n l2RefundL2Address, // destAddr destination L2 contract address\\n valueToReturn, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n \\\"\\\" // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(aliasedL2HubPoolAddress, \\\"\\\");\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"useless function\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x28e520a2456ac047fca4e21aed8d0ce0a4d731941922a83ab56ec12543681f19\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052662386f26fc1000060805264012a05f20060a052621e848060c05273d297fa914353c44b2e33ebe05f21846f1048cfeb6101005234801561004557600080fd5b506040516109633803806109638339810160408190526100649161007a565b6001600160a01b0316610120523360e0526100aa565b60006020828403121561008c57600080fd5b81516001600160a01b03811681146100a357600080fd5b9392505050565b60805160a05160c05160e051610100516101205161082c61013760003960008181610143015261046c01526000818160d501526104e50152600081816101ab01526103a40152600081816101df0152818161026901526104070152600081816101770152818161028b0152610433015260008181610228015281816102b501526103d5015261082c6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631cf3ec03146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a3660046105fd565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610679565b610345565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610788565b6102d9907f00000000000000000000000000000000000000000000000000000000000000006107c5565b905090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f7573656c6573732066756e6374696f6e0000000000000000000000000000000060448201526064015b60405180910390fd5b60008180602001905181019061035b91906107dd565b9050600061036761055b565b6040517f1b871c8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301819052602483018690527f000000000000000000000000000000000000000000000000000000000000000060448401526064830181905260848301527f000000000000000000000000000000000000000000000000000000000000000063ffffffff1660a48301527f000000000000000000000000000000000000000000000000000000000000000060c483015261010060e483015260006101048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631b871c8d9083906101240160206040518083038185885af11580156104b9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104de91906107dd565b50604080517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020810182905260008183015290517f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac49181900360600190a150505050565b600061056561025d565b9050804710156105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e63650000000000000000604482015260640161033c565b90565b803573ffffffffffffffffffffffffffffffffffffffff811681146105f857600080fd5b919050565b6000806000806080858703121561061357600080fd5b61061c856105d4565b935061062a602086016105d4565b92506040850135915061063f606086016105d4565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561068c57600080fd5b610695836105d4565b9150602083013567ffffffffffffffff808211156106b257600080fd5b818501915085601f8301126106c657600080fd5b8135818111156106d8576106d861064a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071e5761071e61064a565b8160405282815288602084870101111561073757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156107c0576107c0610759565b500290565b600082198211156107d8576107d8610759565b500190565b6000602082840312156107ef57600080fd5b505191905056fea2646970667358221220d8698f702b3480c3be52c8e3f34a23d2bb2883baed6d88c84ca110c226d46c4464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631cf3ec03146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a3660046105fd565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610679565b610345565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610788565b6102d9907f00000000000000000000000000000000000000000000000000000000000000006107c5565b905090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f7573656c6573732066756e6374696f6e0000000000000000000000000000000060448201526064015b60405180910390fd5b60008180602001905181019061035b91906107dd565b9050600061036761055b565b6040517f1b871c8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301819052602483018690527f000000000000000000000000000000000000000000000000000000000000000060448401526064830181905260848301527f000000000000000000000000000000000000000000000000000000000000000063ffffffff1660a48301527f000000000000000000000000000000000000000000000000000000000000000060c483015261010060e483015260006101048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631b871c8d9083906101240160206040518083038185885af11580156104b9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104de91906107dd565b50604080517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020810182905260008183015290517f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac49181900360600190a150505050565b600061056561025d565b9050804710156105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e63650000000000000000604482015260640161033c565b90565b803573ffffffffffffffffffffffffffffffffffffffff811681146105f857600080fd5b919050565b6000806000806080858703121561061357600080fd5b61061c856105d4565b935061062a602086016105d4565b92506040850135915061063f606086016105d4565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561068c57600080fd5b610695836105d4565b9150602083013567ffffffffffffffff808211156106b257600080fd5b818501915085601f8301126106c657600080fd5b8135818111156106d8576106d861064a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561071e5761071e61064a565b8160405282815288602084870101111561073757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156107c0576107c0610759565b500290565b600082198211156107d8576107d8610759565b500190565b6000602082840312156107ef57600080fd5b505191905056fea2646970667358221220d8698f702b3480c3be52c8e3f34a23d2bb2883baed6d88c84ca110c226d46c4464736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Arbitrum_SendTokensAdapter.json b/deployments/mainnet/Arbitrum_SendTokensAdapter.json index 6901af75..025f4828 100644 --- a/deployments/mainnet/Arbitrum_SendTokensAdapter.json +++ b/deployments/mainnet/Arbitrum_SendTokensAdapter.json @@ -206,7 +206,7 @@ "args": ["0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef"], "numDeployments": 1, "solcInputHash": "778ed9956c3f76e793496228f16e1373", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"details\":\"This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens the Arbitrum_SpokePool out of the HubPool.\",\"params\":{\"message\":\"The encoded address of the ERC20 to send to the rescue address.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger this function.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool received a duplicate root bundle relay, due to some replay issue.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":\"Arbitrum_SendTokensAdapter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n\\n function unsafeCreateRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xf01d3a899cdeec331b26bbe416cb22f500142002d3ad4c182e01cd44c17d5d11\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport { ArbitrumL1ERC20GatewayLike } from \\\"./Arbitrum_Adapter.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\\n * received a duplicate root bundle relay, due to some replay issue.\\n */\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n uint256 public immutable l2GasPrice = 5e9;\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\\n * this function.\\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\\n * the Arbitrum_SpokePool out of the HubPool.\\n * @param message The encoded address of the ERC20 to send to the rescue address.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n target,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n\\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\\n // emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"relayTokens disabled\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45bafc3f5136bc882620977850a7c4a1d0ee65d69fb65eb165496714e91f536f\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"RELAY_TOKENS_L2_GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"details\":\"This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens the Arbitrum_SpokePool out of the HubPool.\",\"params\":{\"message\":\"The encoded address of the ERC20 to send to the rescue address.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger this function.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Should never be called.\"}},\"notice\":\"This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool received a duplicate root bundle relay, due to some replay issue.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":\"Arbitrum_SendTokensAdapter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n\\n function unsafeCreateRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function outboundTransferCustomRefund(\\n address _token,\\n address _refundTo,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\\n\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\\n l1Token,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n } else {\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n to,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue(l2GasLimit);\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xf01d3a899cdeec331b26bbe416cb22f500142002d3ad4c182e01cd44c17d5d11\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport { ArbitrumL1ERC20GatewayLike } from \\\"./Arbitrum_Adapter.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\\n * received a duplicate root bundle relay, due to some replay issue.\\n */\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n uint256 public immutable l2GasPrice = 5e9;\\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n }\\n\\n /**\\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\\n * this function.\\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\\n * the Arbitrum_SpokePool out of the HubPool.\\n * @param message The encoded address of the ERC20 to send to the rescue address.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\\n\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n\\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\\n l1Token,\\n l2RefundL2Address,\\n target,\\n amount,\\n RELAY_TOKENS_L2_GAS_LIMIT,\\n l2GasPrice,\\n data\\n );\\n\\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\\n // emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Should never be called.\\n */\\n function relayTokens(\\n address,\\n address,\\n uint256,\\n address\\n ) external payable override {\\n revert(\\\"relayTokens disabled\\\");\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0x45bafc3f5136bc882620977850a7c4a1d0ee65d69fb65eb165496714e91f536f\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60e0346100b357601f610c6738819003918201601f19168301916001600160401b038311848410176100b8578084926020946040528339810103126100b357516001600160a01b03811681036100b357662386f26fc1000060805264012a05f20060a05260c052604051610b9890816100cf82396080518181816102f9015281816106a00152610b3b015260a05181818161037a015281816107440152610b06015260c05181818161015001526108ad0152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe6040608081526004908136101561001557600080fd5b600090813560e01c806308f1ed15146108d15780631ba4a9cb1461086357806328f2716e1461082857806352c8c75c146107675780639ae366851461070f5780639c3ba200146106c3578063e599477e1461066b5763e6eb8ade1461007957600080fd5b807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576100aa610912565b9260249081359167ffffffffffffffff9182841161043057366023850112156104305783810135936100db856109c6565b906100e887519283610985565b858252602095868301913686838301011161066357818a92878a9301853784010152868280518101031261065f57519173ffffffffffffffffffffffffffffffffffffffff9182841680940361065b57870151610143610b00565b92834710610600578086917f0000000000000000000000000000000000000000000000000000000000000000169b898d8c51948580927fbda009fe0000000000000000000000000000000000000000000000000000000082528b8a8301525afa9283156105f6578c936105ba575b50818b51937fdd62ed3e00000000000000000000000000000000000000000000000000000000855230878601521680898501526044938b8186818c5afa80156105ae5786908f90610579575b6102079250610a66565b908c51918c8301917f095ea7b30000000000000000000000000000000000000000000000000000000083528b840152858301528482526102468261093a565b8c51918d83018381108d82111761054d578e528c83527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648d840152893b156104f2578e8e818f938d6102c4979683809351925af1913d156104e6573d6102b76102ae826109c6565b93519384610985565b825281933d92013e610aa2565b80518061043e575b50508b9c95938b9c989795936103af938c938e73428ab2ba90eba0a4be7af34c9ac451ab061ac0109f51957f00000000000000000000000000000000000000000000000000000000000000009087015280808701528c6060870152606086526103348661093a565b519e8f9b8c9a8b997f4fb1a07b000000000000000000000000000000000000000000000000000000008b528a015288015216908501526064840152620493e060848401527f000000000000000000000000000000000000000000000000000000000000000060a484015260e060c484015260e4830190610a23565b03925af18015610434576103c1578480f35b3d8086853e6103d08185610985565b830192828185031261043057805191821161043057019082601f8301121561042c5781519261040a610401856109c6565b95519586610985565b83855281848401011161042c578061042494019101610a00565b388080808480f35b8480fd5b8580fd5b84513d87823e3d90fd5b818c91810103126104e2578a01518015908115036104e2576104615738806102cc565b6084857f5361666545524332303a204552433230206f7065726174696f6e20646964206e85602a8f8f8e9151957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8c80fd5b50509050606090610aa2565b8d517f08c379a00000000000000000000000000000000000000000000000000000000081528089018e9052601d818d01527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081880152606490fd5b508a8f60418a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50508b81813d83116105a7575b6105908183610985565b810103126105a3578561020791516101fd565b8d80fd5b503d610586565b8e8e51903d90823e3d90fd5b9092508981813d83116105ef575b6105d28183610985565b810103126105eb575181811681036105eb5791386101b1565b8b80fd5b503d6105c8565b8b513d8e823e3d90fd5b6064836018888b8d51937f08c379a00000000000000000000000000000000000000000000000000000000085528401528201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152fd5b8880fd5b8780fd5b8980fd5b5080fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173428ab2ba90eba0a4be7af34c9ac451ab061ac0108152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50919060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108255761079c610912565b5073ffffffffffffffffffffffffffffffffffffffff6024358181160361066757606435908116036108255750602060649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601460248201527f72656c6179546f6b656e732064697361626c65640000000000000000000000006044820152fd5b80fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209051620493e08152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209061090b610b00565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361093557565b600080fd5b6080810190811067ffffffffffffffff82111761095657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761095657604052565b67ffffffffffffffff811161095657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110610a135750506000910152565b8181015183820152602001610a03565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610a5f81518092818752878088019101610a00565b0116010190565b91908201809211610a7357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90919015610aae575090565b815115610abe5750805190602001fd5b610afc906040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352602060048401526024830190610a23565b0390fd5b620493e07f0000000000000000000000000000000000000000000000000000000000000000818102918115918304141715610a7357610b5f907f0000000000000000000000000000000000000000000000000000000000000000610a66565b9056fea26469706673582212204720938d7cb043f3ec85ed4a591ecd87e9eda6b87236ec70d1fbafbb1b476c2f64736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600090813560e01c806308f1ed15146108d15780631ba4a9cb1461086357806328f2716e1461082857806352c8c75c146107675780639ae366851461070f5780639c3ba200146106c3578063e599477e1461066b5763e6eb8ade1461007957600080fd5b807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576100aa610912565b9260249081359167ffffffffffffffff9182841161043057366023850112156104305783810135936100db856109c6565b906100e887519283610985565b858252602095868301913686838301011161066357818a92878a9301853784010152868280518101031261065f57519173ffffffffffffffffffffffffffffffffffffffff9182841680940361065b57870151610143610b00565b92834710610600578086917f0000000000000000000000000000000000000000000000000000000000000000169b898d8c51948580927fbda009fe0000000000000000000000000000000000000000000000000000000082528b8a8301525afa9283156105f6578c936105ba575b50818b51937fdd62ed3e00000000000000000000000000000000000000000000000000000000855230878601521680898501526044938b8186818c5afa80156105ae5786908f90610579575b6102079250610a66565b908c51918c8301917f095ea7b30000000000000000000000000000000000000000000000000000000083528b840152858301528482526102468261093a565b8c51918d83018381108d82111761054d578e528c83527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648d840152893b156104f2578e8e818f938d6102c4979683809351925af1913d156104e6573d6102b76102ae826109c6565b93519384610985565b825281933d92013e610aa2565b80518061043e575b50508b9c95938b9c989795936103af938c938e73428ab2ba90eba0a4be7af34c9ac451ab061ac0109f51957f00000000000000000000000000000000000000000000000000000000000000009087015280808701528c6060870152606086526103348661093a565b519e8f9b8c9a8b997f4fb1a07b000000000000000000000000000000000000000000000000000000008b528a015288015216908501526064840152620493e060848401527f000000000000000000000000000000000000000000000000000000000000000060a484015260e060c484015260e4830190610a23565b03925af18015610434576103c1578480f35b3d8086853e6103d08185610985565b830192828185031261043057805191821161043057019082601f8301121561042c5781519261040a610401856109c6565b95519586610985565b83855281848401011161042c578061042494019101610a00565b388080808480f35b8480fd5b8580fd5b84513d87823e3d90fd5b818c91810103126104e2578a01518015908115036104e2576104615738806102cc565b6084857f5361666545524332303a204552433230206f7065726174696f6e20646964206e85602a8f8f8e9151957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8c80fd5b50509050606090610aa2565b8d517f08c379a00000000000000000000000000000000000000000000000000000000081528089018e9052601d818d01527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081880152606490fd5b508a8f60418a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50508b81813d83116105a7575b6105908183610985565b810103126105a3578561020791516101fd565b8d80fd5b503d610586565b8e8e51903d90823e3d90fd5b9092508981813d83116105ef575b6105d28183610985565b810103126105eb575181811681036105eb5791386101b1565b8b80fd5b503d6105c8565b8b513d8e823e3d90fd5b6064836018888b8d51937f08c379a00000000000000000000000000000000000000000000000000000000085528401528201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152fd5b8880fd5b8780fd5b8980fd5b5080fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173428ab2ba90eba0a4be7af34c9ac451ab061ac0108152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50919060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126108255761079c610912565b5073ffffffffffffffffffffffffffffffffffffffff6024358181160361066757606435908116036108255750602060649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601460248201527f72656c6179546f6b656e732064697361626c65640000000000000000000000006044820152fd5b80fd5b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209051620493e08152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610667576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461066757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106675760209061090b610b00565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361093557565b600080fd5b6080810190811067ffffffffffffffff82111761095657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761095657604052565b67ffffffffffffffff811161095657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110610a135750506000910152565b8181015183820152602001610a03565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610a5f81518092818752878088019101610a00565b0116010190565b91908201809211610a7357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90919015610aae575090565b815115610abe5750805190602001fd5b610afc906040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352602060048401526024830190610a23565b0390fd5b620493e07f0000000000000000000000000000000000000000000000000000000000000000818102918115918304141715610a7357610b5f907f0000000000000000000000000000000000000000000000000000000000000000610a66565b9056fea26469706673582212204720938d7cb043f3ec85ed4a591ecd87e9eda6b87236ec70d1fbafbb1b476c2f64736f6c63430008120033", "devdoc": { diff --git a/deployments/mainnet/Boba_Adapter.json b/deployments/mainnet/Boba_Adapter.json index c0c9e53e..5bcea16a 100644 --- a/deployments/mainnet/Boba_Adapter.json +++ b/deployments/mainnet/Boba_Adapter.json @@ -194,7 +194,7 @@ ], "numDeployments": 1, "solcInputHash": "80d9895099d6448454133a653020a62d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Boba system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Boba that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Boba.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Boba.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter that excludes the custom bridging logic.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Boba_Adapter.sol\":\"Boba_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Boba_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\\n * that excludes the custom bridging logic.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Boba.\\n * @param target Contract on Boba that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Boba.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x49d48d71aa747ab7deb11ed446f28e7c976b11d7df85e7b97261b3d2c54cfb0e\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Boba system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Boba that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Boba.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Boba.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter that excludes the custom bridging logic.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Boba_Adapter.sol\":\"Boba_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Boba_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\\n * that excludes the custom bridging logic.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\n\\n// solhint-disable-next-line contract-name-camelcase\\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Boba.\\n * @param target Contract on Boba that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes calldata message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Boba.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x49d48d71aa747ab7deb11ed446f28e7c976b11d7df85e7b97261b3d2c54cfb0e\",\"license\":\"AGPL-3.0-only\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610100604052621e848060a05234801561001857600080fd5b50604051610e93380380610e938339810160408190526100379161006c565b6001600160a01b0391821660805291811660c0521660e0526100b9565b6001600160a01b038116811461006957600080fd5b50565b60008060006060848603121561008157600080fd5b835161008c81610054565b602085015190935061009d81610054565b60408501519092506100ae81610054565b809150509250925092565b60805160a05160c05160e051610d6b61012860003960008181607c01528181610311015261037801526000818160da015281816101a30152610223015260008181610157015281816102dc0152818161041901526104f701526000818161010e01526106d50152610d6b6000f3fe6080604052600436106100655760003560e01c806352c8c75c1161004357806352c8c75c14610130578063cf6e65b714610145578063e6eb8ade1461018e57600080fd5b8063078f29cf1461006a578063146bf4b1146100c85780633cb747bf146100fc575b600080fd5b34801561007657600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156100d457600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561010857600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b61014361013e366004610a89565b6101a1565b005b34801561015157600080fd5b506101797f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100bf565b61014361019c366004610ad6565b6104f1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610376576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561035857600080fd5b505af115801561036c573d6000803e3d6000fd5b505050505061048c565b7f00000000000000000000000000000000000000000000000000000000000000006103b873ffffffffffffffffffffffffffffffffffffffff8616828561055d565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61051d837f00000000000000000000000000000000000000000000000000000000000000008484610698565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161055093929190610ba2565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190610bdb565b6106029190610bf4565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610692908590610748565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610710908790869086908990600401610c33565b600060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b5050505050505050565b60006107aa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661085e9092919063ffffffff16565b80519091501561085957808060200190518101906107c89190610c7a565b610859576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061086d8484600085610877565b90505b9392505050565b606082471015610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610850565b73ffffffffffffffffffffffffffffffffffffffff85163b610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610850565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109b09190610cc8565b60006040518083038185875af1925050503d80600081146109ed576040519150601f19603f3d011682016040523d82523d6000602084013e6109f2565b606091505b5091509150610a02828286610a0d565b979650505050505050565b60608315610a1c575081610870565b825115610a2c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108509190610ce4565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a8457600080fd5b919050565b60008060008060808587031215610a9f57600080fd5b610aa885610a60565b9350610ab660208601610a60565b925060408501359150610acb60608601610a60565b905092959194509250565b600080600060408486031215610aeb57600080fd5b610af484610a60565b9250602084013567ffffffffffffffff80821115610b1157600080fd5b818601915086601f830112610b2557600080fd5b813581811115610b3457600080fd5b876020828501011115610b4657600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610bd2604083018486610b59565b95945050505050565b600060208284031215610bed57600080fd5b5051919050565b60008219821115610c2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610c63606083018587610b59565b905063ffffffff8316604083015295945050505050565b600060208284031215610c8c57600080fd5b8151801515811461087057600080fd5b60005b83811015610cb7578181015183820152602001610c9f565b838111156106925750506000910152565b60008251610cda818460208701610c9c565b9190910192915050565b6020815260008251806020840152610d03816040850160208701610c9c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212207f9bba09fc32ab805ba4eedd30279030757c69a4a4b12e51aea2f961db2c1e5864736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100655760003560e01c806352c8c75c1161004357806352c8c75c14610130578063cf6e65b714610145578063e6eb8ade1461018e57600080fd5b8063078f29cf1461006a578063146bf4b1146100c85780633cb747bf146100fc575b600080fd5b34801561007657600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156100d457600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561010857600080fd5b5061009e7f000000000000000000000000000000000000000000000000000000000000000081565b61014361013e366004610a89565b6101a1565b005b34801561015157600080fd5b506101797f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100bf565b61014361019c366004610ad6565b6104f1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610376576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561027c57600080fd5b505af1158015610290573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561035857600080fd5b505af115801561036c573d6000803e3d6000fd5b505050505061048c565b7f00000000000000000000000000000000000000000000000000000000000000006103b873ffffffffffffffffffffffffffffffffffffffff8616828561055d565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561047257600080fd5b505af1158015610486573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61051d837f00000000000000000000000000000000000000000000000000000000000000008484610698565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161055093929190610ba2565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190610bdb565b6106029190610bf4565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610692908590610748565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610710908790869086908990600401610c33565b600060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b5050505050505050565b60006107aa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661085e9092919063ffffffff16565b80519091501561085957808060200190518101906107c89190610c7a565b610859576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061086d8484600085610877565b90505b9392505050565b606082471015610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610850565b73ffffffffffffffffffffffffffffffffffffffff85163b610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610850565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109b09190610cc8565b60006040518083038185875af1925050503d80600081146109ed576040519150601f19603f3d011682016040523d82523d6000602084013e6109f2565b606091505b5091509150610a02828286610a0d565b979650505050505050565b60608315610a1c575081610870565b825115610a2c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108509190610ce4565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a8457600080fd5b919050565b60008060008060808587031215610a9f57600080fd5b610aa885610a60565b9350610ab660208601610a60565b925060408501359150610acb60608601610a60565b905092959194509250565b600080600060408486031215610aeb57600080fd5b610af484610a60565b9250602084013567ffffffffffffffff80821115610b1157600080fd5b818601915086601f830112610b2557600080fd5b813581811115610b3457600080fd5b876020828501011115610b4657600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610bd2604083018486610b59565b95945050505050565b600060208284031215610bed57600080fd5b5051919050565b60008219821115610c2e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610c63606083018587610b59565b905063ffffffff8316604083015295945050505050565b600060208284031215610c8c57600080fd5b8151801515811461087057600080fd5b60005b83811015610cb7578181015183820152602001610c9f565b838111156106925750506000910152565b60008251610cda818460208701610c9c565b9190910192915050565b6020815260008251806020840152610d03816040850160208701610c9c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212207f9bba09fc32ab805ba4eedd30279030757c69a4a4b12e51aea2f961db2c1e5864736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Ethereum_Adapter.json b/deployments/mainnet/Ethereum_Adapter.json index 79ebc869..feb62a92 100644 --- a/deployments/mainnet/Ethereum_Adapter.json +++ b/deployments/mainnet/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\r\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\r\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\r\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\r\\n * and the Ethereum_SpokePool.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Ethereum_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /**\\r\\n * @notice Send message to target on Ethereum.\\r\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\r\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\r\\n * send messages via this pass-through contract.\\r\\n * @param target Contract that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n _executeCall(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send tokens to target.\\r\\n * @param l1Token L1 token to send.\\r\\n * @param l2Token Unused parameter in this contract.\\r\\n * @param amount Amount of L1 tokens to send.\\r\\n * @param to recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\r\\n // on this network.\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n IERC20(l1Token).safeTransfer(to, amount);\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n\\r\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\r\\n function _executeCall(address to, bytes memory data) private {\\r\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\r\\n\\r\\n bool success;\\r\\n\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly {\\r\\n let inputData := add(data, 0x20)\\r\\n let inputDataSize := mload(data)\\r\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\r\\n // value cross-chain.\\r\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\r\\n }\\r\\n require(success, \\\"execute call failed\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x3342701f53c0a9fb9700a20552e08780e20708e9f69a77948f68d46ce33b0959\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107d6806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c3660046105a7565b610056565b005b6100416100513660046105f4565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff8516828461015c565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b61011c8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101ee92505050565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161014f93929190610677565b60405180910390a1505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101e9908490610270565b505050565b600060208201825160008082846000895af192505050806101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60006102d2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661037c9092919063ffffffff16565b8051909150156101e957808060200190518101906102f091906106e1565b6101e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610267565b606061038b8484600085610395565b90505b9392505050565b606082471015610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610267565b73ffffffffffffffffffffffffffffffffffffffff85163b6104a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610267565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104ce9190610733565b60006040518083038185875af1925050503d806000811461050b576040519150601f19603f3d011682016040523d82523d6000602084013e610510565b606091505b509150915061052082828661052b565b979650505050505050565b6060831561053a57508161038e565b82511561054a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610267919061074f565b803573ffffffffffffffffffffffffffffffffffffffff811681146105a257600080fd5b919050565b600080600080608085870312156105bd57600080fd5b6105c68561057e565b93506105d46020860161057e565b9250604085013591506105e96060860161057e565b905092959194509250565b60008060006040848603121561060957600080fd5b6106128461057e565b9250602084013567ffffffffffffffff8082111561062f57600080fd5b818601915086601f83011261064357600080fd5b81358181111561065257600080fd5b87602082850101111561066457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156106f357600080fd5b8151801515811461038e57600080fd5b60005b8381101561071e578181015183820152602001610706565b8381111561072d576000848401525b50505050565b60008251610745818460208701610703565b9190910192915050565b602081526000825180602084015261076e816040850160208701610703565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200e5945862d37aa7aba63062b50564dca89a47f3e2e8f804d3dfc6cc495a9a36264736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Ethereum_SpokePool.json b/deployments/mainnet/Ethereum_SpokePool.json index 6ab8bc18..d64a6c4b 100644 --- a/deployments/mainnet/Ethereum_SpokePool.json +++ b/deployments/mainnet/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 1, "solcInputHash": "ac469a0c874627ad85d8b93b55e7f3fc", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b506040516200466b3803806200466b8339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b608051614382620002e9600039600081816101d901528181610ce601528181610daf0152818161234d01528181612bd30152612c2901526143826000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b5061024561024036600461366d565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613769565b6106b0565b3480156102a057600080fd5b506102456102af366004613784565b61073d565b3480156102c057600080fd5b506102456102cf3660046137ab565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137eb565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b61024561032536600461381e565b610ab1565b34801561033657600080fd5b50610245610345366004613884565b610f28565b34801561035657600080fd5b506103856103653660046138a6565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138d0565b6110cf565b34801561044d57600080fd5b5061024561045c366004613784565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e636600461396e565b6112ff565b60405161021c9190613a59565b34801561050457600080fd5b50610245610513366004613ad9565b6114d9565b34801561052457600080fd5b50610245610533366004613769565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c37565b6115ab565b34801561059157600080fd5b506105a56105a0366004613784565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d5366004613784565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613769565b611737565b34801561061357600080fd5b50610245610622366004613ca6565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611dff565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e80565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611dff565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611dff565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d84565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dcc565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613df1565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f6c565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612048565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e19565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611dff565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120d9565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612150565b905060006111c782848b886000612180565b90506111d882828a8887600061242d565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611dff565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e3c565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134b1565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e3c565b90506020028101906113eb9190613e6b565b6040516113f9929190613ed0565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613ee0565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b808484815181106114b2576114b2613e3c565b6020026020010181905250505080806114ca90613f61565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61256f565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611dff565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126ee565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127da565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613f99565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120d9565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127da565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612150565b9050600061196982848d896000612180565b905061197a82828c8987600061242d565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e3c565b90600052602060002090600302019050611b6d81600101548484612877565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128b4565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff166128f5565b60408301515160005b81811015611cf957600085604001518281518110611c9157611c91613e3c565b602002602001015190506000811115611cf057611cf08660a001518381518110611cbd57611cbd613e3c565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50600101611c71565b50835115611d9257611d0a84612989565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611d8992919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611df095949392919061403d565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611efd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a2d565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081604051602001612163919061409b565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121b857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61221e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b606085015160008781526005602052604090205410612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122a957506000612424565b6122c284848760c001516122bd9190614142565b612b39565b600087815260056020526040812054606088015192935086926122e59190614165565b90508281101561230e5780925061230b83868960c001516123069190614142565b612b73565b91505b6000888152600560205260408120805485929061232c90849061417c565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123b457836123a15760408701516123a19073ffffffffffffffffffffffffffffffffffffffff16333085611f6c565b6123af876020015183612b9c565b612421565b836123ee576123af338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f6c909392919063ffffffff16565b612421876020015183896040015173ffffffffffffffffffffffffffffffffffffffff166129339092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161255f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264460038463ffffffff168154811061262b5761262b613e3c565b9060005260206000209060030201600001548284612cdd565b6126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126b582612150565b905060006126cc8284856060015160006001612180565b90506126de828260008087600161242d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811661276b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286182612cf5565b905061286e878285612d30565b50505050505050565b60006128aa82858560405160200161288f9190614194565b60405160208183030381529060405280519060200120612dce565b90505b9392505050565b6000806128c36101008461425e565b905060006128d361010085614272565b6000928352602095909552506040902054600190931b92831690921492915050565b60006129036101008361425e565b9050600061291361010084614272565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fc6565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614286565b6000612a8f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612de49092919063ffffffff16565b8051909150156106ab5780806020019051810190612aad9190614286565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b4d82670de0b6b3a76400006142a3565b67ffffffffffffffff16612b6984670de0b6b3a76400006142c4565b6128ad919061425e565b6000670de0b6b3a7640000612b8883826142a3565b612b699067ffffffffffffffff16856142c4565b73ffffffffffffffffffffffffffffffffffffffff82163b15612bfa5761103e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612933565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8257600080fd5b505af1158015612c96573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128aa82858560405160200161288f919061409b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612163565b612d3a8282612df3565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612ddb8584612e17565b14949350505050565b60606128aa8484600085612e83565b6000806000612e028585613019565b91509150612e0f81613087565b509392505050565b600081815b8451811015612e0f576000858281518110612e3957612e39613e3c565b60200260200101519050808311612e5f5760008381526020829052604090209250612e70565b600081815260208490526040902092505b5080612e7b81613f61565b915050612e1c565b606082471015612f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fbc9190614301565b60006040518083038185875af1925050503d8060008114612ff9576040519150601f19603f3d011682016040523d82523d6000602084013e612ffe565b606091505b509150915061300e8282866132db565b979650505050505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561332e565b94509450505050613080565b8251604003613078576020830151604084015161306d868383613446565b935093505050613080565b506000905060025b9250929050565b600081600481111561309b5761309b61431d565b036130a35750565b60018160048111156130b7576130b761431d565b0361311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b60028160048111156131325761313261431d565b03613199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131ad576131ad61431d565b0361323a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561324e5761324e61431d565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132ea5750816128ad565b8251156132fa5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f4e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613365575060009050600361343d565b8460ff16601b1415801561337d57508460ff16601c14155b1561338e575060009050600461343d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133e2573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166134365760006001925092505061343d565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161347c60ff86901c601b61417c565b905061348a8782888561332e565b935093505050935093915050565b803563ffffffff811681146134ac57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613503576135036134b1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613550576135506134b1565b604052919050565b600067ffffffffffffffff821115613572576135726134b1565b5060051b60200190565b600082601f83011261358d57600080fd5b813560206135a261359d83613558565b613509565b82815260059290921b840181019181810190868411156135c157600080fd5b8286015b848110156135dc57803583529183019183016135c5565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134ac57600080fd5b600082601f83011261361c57600080fd5b8135602061362c61359d83613558565b82815260059290921b8401810191818101908684111561364b57600080fd5b8286015b848110156135dc57613660816135e7565b835291830191830161364f565b60008060006060848603121561368257600080fd5b61368b84613498565b9250602084013567ffffffffffffffff808211156136a857600080fd5b9085019060c082880312156136bc57600080fd5b6136c46134e0565b82358152602083013560208201526040830135828111156136e457600080fd5b6136f08982860161357c565b60408301525061370260608401613498565b6060820152613713608084016135e7565b608082015260a08301358281111561372a57600080fd5b6137368982860161360b565b60a0830152509350604086013591508082111561375257600080fd5b5061375f8682870161357c565b9150509250925092565b60006020828403121561377b57600080fd5b6128ad826135e7565b60006020828403121561379657600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137c057600080fd5b6137c9846135e7565b92506020840135915060408401356137e08161379d565b809150509250925092565b6000602082840312156137fd57600080fd5b6128ad82613498565b803567ffffffffffffffff811681146134ac57600080fd5b60008060008060008060c0878903121561383757600080fd5b613840876135e7565b955061384e602088016135e7565b9450604087013593506060870135925061386a60808801613806565b915061387860a08801613498565b90509295509295509295565b6000806040838503121561389757600080fd5b50508035926020909101359150565b600080604083850312156138b957600080fd5b6138c2836135e7565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138f057600080fd5b6138f98b6135e7565b995061390760208c016135e7565b985061391560408c016135e7565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061393f60e08c01613806565b925061394e6101008c01613806565b915061395d6101208c01613498565b90509295989b9194979a5092959850565b6000806020838503121561398157600080fd5b823567ffffffffffffffff8082111561399957600080fd5b818501915085601f8301126139ad57600080fd5b8135818111156139bc57600080fd5b8660208260051b85010111156139d157600080fd5b60209290920196919550909350505050565b60005b838110156139fe5781810151838201526020016139e6565b838111156117035750506000910152565b60008151808452613a278160208601602086016139e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613acc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613aba858351613a0f565b94509285019290850190600101613a80565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613af957600080fd5b613b028b6135e7565b9950613b1060208c016135e7565b9850613b1e60408c016135e7565b975060608b0135965060808b01359550613b3a60a08c01613806565b9450613b4860c08c01613806565b9350613b5660e08c01613498565b9250613b656101008c01613498565b91506101208b013567ffffffffffffffff811115613b8257600080fd5b613b8e8d828e0161357c565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bba57613bba6134b1565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613bf757600080fd5b8135613c0561359d82613ba0565b818152846020838601011115613c1a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c4d57600080fd5b613c56856135e7565b9350613c6460208601613806565b9250613c7260408601613498565b9150606085013567ffffffffffffffff811115613c8e57600080fd5b613c9a87828801613be6565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cc957600080fd5b613cd28d6135e7565b9b50613ce060208e016135e7565b9a50613cee60408e016135e7565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d1860e08e01613806565b9450613d276101008e01613806565b9350613d366101208e01613806565b9250613d456101408e01613498565b915067ffffffffffffffff6101608e01351115613d6157600080fd5b613d728e6101608f01358f01613be6565b90509295989b509295989b509295989b565b600060208284031215613d9657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613de957613de9613d9d565b039392505050565b600063ffffffff808316818516808303821115613e1057613e10613d9d565b01949350505050565b600063ffffffff808316818103613e3257613e32613d9d565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ea057600080fd5b83018035915067ffffffffffffffff821115613ebb57600080fd5b60200191503681900382131561308057600080fd5b8183823760009101908152919050565b600060208284031215613ef257600080fd5b815167ffffffffffffffff811115613f0957600080fd5b8201601f81018413613f1a57600080fd5b8051613f2861359d82613ba0565b818152856020838501011115613f3d57600080fd5b6124248260208301602086016139e3565b6020815260006128ad6020830184613a0f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9257613f92613d9d565b5060010190565b67ffffffffffffffff831681526040602082015260006128aa6040830184613a0f565b600081518084526020808501945080840160005b83811015613fec57815187529582019590820190600101613fd0565b509495945050505050565b600081518084526020808501945080840160005b83811015613fec57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161400b565b85815260a06020820152600061405660a0830187613fbc565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140858287613ff7565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411060c084018267ffffffffffffffff169052565b5060e083015161412c60e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1057613e10613d9d565b60008282101561417757614177613d9d565b500390565b6000821982111561418f5761418f613d9d565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141c460e0840182613fbc565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526124248282613ff7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261426d5761426d61422f565b500490565b6000826142815761428161422f565b500690565b60006020828403121561429857600080fd5b81516128ad8161379d565b600067ffffffffffffffff83811690831681811015613de957613de9613d9d565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156142fc576142fc613d9d565b500290565b600082516143138184602087016139e3565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea264697066735822122080ae738e10313af516a74677485d3f63d3712d15f7ab22875bb8d6465468b97064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/LpTokenFactory.json b/deployments/mainnet/LpTokenFactory.json index 4c55f8bc..88d7c1e5 100644 --- a/deployments/mainnet/LpTokenFactory.json +++ b/deployments/mainnet/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _concatenate(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _concatenate(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _concatenate(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x5de9a65b9febf4fc9d57a88f0b574880c4e72823eb55a0419a45ffe2f10f1036\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a2646970667358221220fc6b5b9990ae8263f246bfac8e22e56baac0641f6392528007bb7452a359f2c564736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Optimism_Adapter.json b/deployments/mainnet/Optimism_Adapter.json index 32447c6c..64a76183 100644 --- a/deployments/mainnet/Optimism_Adapter.json +++ b/deployments/mainnet/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "2433465a1be70a13b6719df6fea2831a", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"invalid cross domain messenger\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"invalid cross domain sender\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes calldata _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x6aef2e221ee152c96baa26ee12889f06fcc160c2cb84948aca98c92e46c36e71\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\r\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\r\\nimport \\\"./CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n uint32 public immutable l2GasLimit = 2_000_000;\\r\\n\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n IL1StandardBridge public immutable l1StandardBridge;\\r\\n\\r\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\r\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\r\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\r\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\r\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\r\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\r\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\r\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\r\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\r\\n * @param _l1StandardBridge Standard bridge contract.\\r\\n */\\r\\n constructor(\\r\\n WETH9 _l1Weth,\\r\\n address _crossDomainMessenger,\\r\\n IL1StandardBridge _l1StandardBridge\\r\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\r\\n l1Weth = _l1Weth;\\r\\n l1StandardBridge = _l1StandardBridge;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Optimism.\\r\\n * @param target Contract on Optimism that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Optimism.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\r\\n } else {\\r\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\r\\n\\r\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\r\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\r\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\r\\n\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\r\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xf6248840bb1c94212711d2acc106eaa606ce663d3e67d4e430f813bab445876c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052621e848060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161113538038061113583398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f606101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108ca0152610f606000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c7e565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610ccb565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff86168285610752565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610712837f0000000000000000000000000000000000000000000000000000000000000000848461088d565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161074593929190610d97565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610dd0565b6107f79190610de9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061088790859061093d565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b90610905908790869086908990600401610e28565b600060405180830381600087803b15801561091f57600080fd5b505af1158015610933573d6000803e3d6000fd5b5050505050505050565b600061099f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a539092919063ffffffff16565b805190915015610a4e57808060200190518101906109bd9190610e6f565b610a4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a628484600085610a6c565b90505b9392505050565b606082471015610afe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a45565b73ffffffffffffffffffffffffffffffffffffffff85163b610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a45565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ba59190610ebd565b60006040518083038185875af1925050503d8060008114610be2576040519150601f19603f3d011682016040523d82523d6000602084013e610be7565b606091505b5091509150610bf7828286610c02565b979650505050505050565b60608315610c11575081610a65565b825115610c215782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a459190610ed9565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b919050565b60008060008060808587031215610c9457600080fd5b610c9d85610c55565b9350610cab60208601610c55565b925060408501359150610cc060608601610c55565b905092959194509250565b600080600060408486031215610ce057600080fd5b610ce984610c55565b9250602084013567ffffffffffffffff80821115610d0657600080fd5b818601915086601f830112610d1a57600080fd5b813581811115610d2957600080fd5b876020828501011115610d3b57600080fd5b6020830194508093505050509250925092565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dc7604083018486610d4e565b95945050505050565b600060208284031215610de257600080fd5b5051919050565b60008219821115610e23577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201526000610e58606083018587610d4e565b905063ffffffff8316604083015295945050505050565b600060208284031215610e8157600080fd5b81518015158114610a6557600080fd5b60005b83811015610eac578181015183820152602001610e94565b838111156108875750506000910152565b60008251610ecf818460208701610e91565b9190910192915050565b6020815260008251806020840152610ef8816040850160208701610e91565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220b1dcd296f329363815b843419c7d2e55bf740c719fbf2b33924028fa7f9acec064736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/PolygonTokenBridger.json b/deployments/mainnet/PolygonTokenBridger.json index ea947bd4..13ab1495 100644 --- a/deployments/mainnet/PolygonTokenBridger.json +++ b/deployments/mainnet/PolygonTokenBridger.json @@ -203,7 +203,7 @@ ], "numDeployments": 2, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/Polygon_Adapter.json b/deployments/mainnet/Polygon_Adapter.json index be7f01a6..55566036 100644 --- a/deployments/mainnet/Polygon_Adapter.json +++ b/deployments/mainnet/Polygon_Adapter.json @@ -238,7 +238,7 @@ ], "numDeployments": 1, "solcInputHash": "b20d5afcf396996ae08652b8281973a7", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract DepositManager\",\"name\":\"_depositManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_erc20Predicate\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Matic\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"depositManager\",\"outputs\":[{\"internalType\":\"contract DepositManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"erc20Predicate\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Matic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_depositManager\":\"DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\",\"_erc20Predicate\":\"ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\",\"_fxStateSender\":\"FxStateSender Polygon system contract to send arbitrary messages to L2.\",\"_l1Matic\":\"matic address on l1.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\ninterface IRootChainManager {\\r\\n function depositEtherFor(address user) external payable;\\r\\n\\r\\n function depositFor(\\r\\n address user,\\r\\n address rootToken,\\r\\n bytes calldata depositData\\r\\n ) external;\\r\\n}\\r\\n\\r\\ninterface IFxStateSender {\\r\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\r\\n}\\r\\n\\r\\ninterface DepositManager {\\r\\n function depositERC20ForUser(\\r\\n address token,\\r\\n address user,\\r\\n uint256 amount\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Sends cross chain messages Polygon L2 network.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Polygon_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n IRootChainManager public immutable rootChainManager;\\r\\n IFxStateSender public immutable fxStateSender;\\r\\n DepositManager public immutable depositManager;\\r\\n address public immutable erc20Predicate;\\r\\n address public immutable l1Matic;\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\\r\\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\\r\\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\\r\\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\\r\\n * @param _l1Matic matic address on l1.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n */\\r\\n constructor(\\r\\n IRootChainManager _rootChainManager,\\r\\n IFxStateSender _fxStateSender,\\r\\n DepositManager _depositManager,\\r\\n address _erc20Predicate,\\r\\n address _l1Matic,\\r\\n WETH9 _l1Weth\\r\\n ) {\\r\\n rootChainManager = _rootChainManager;\\r\\n fxStateSender = _fxStateSender;\\r\\n depositManager = _depositManager;\\r\\n erc20Predicate = _erc20Predicate;\\r\\n l1Matic = _l1Matic;\\r\\n l1Weth = _l1Weth;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Polygon.\\r\\n * @param target Contract on Polygon that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n fxStateSender.sendMessageToChild(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Polygon.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n rootChainManager.depositEtherFor{ value: amount }(to);\\r\\n } else if (l1Token == l1Matic) {\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\\r\\n depositManager.depositERC20ForUser(l1Token, to, amount);\\r\\n } else {\\r\\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\\r\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xac06498e0b896c0365fe8410417d10bcc02a4de509a3b815b43cc5e48d91552d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract DepositManager\",\"name\":\"_depositManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_erc20Predicate\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Matic\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"depositManager\",\"outputs\":[{\"internalType\":\"contract DepositManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"erc20Predicate\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Matic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_depositManager\":\"DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\",\"_erc20Predicate\":\"ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\",\"_fxStateSender\":\"FxStateSender Polygon system contract to send arbitrary messages to L2.\",\"_l1Matic\":\"matic address on l1.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\r\\nimport \\\"../interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\ninterface IRootChainManager {\\r\\n function depositEtherFor(address user) external payable;\\r\\n\\r\\n function depositFor(\\r\\n address user,\\r\\n address rootToken,\\r\\n bytes calldata depositData\\r\\n ) external;\\r\\n}\\r\\n\\r\\ninterface IFxStateSender {\\r\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\r\\n}\\r\\n\\r\\ninterface DepositManager {\\r\\n function depositERC20ForUser(\\r\\n address token,\\r\\n address user,\\r\\n uint256 amount\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Sends cross chain messages Polygon L2 network.\\r\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\r\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\r\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\r\\n * that call this contract's logic guard against reentrancy.\\r\\n */\\r\\n\\r\\n// solhint-disable-next-line contract-name-camelcase\\r\\ncontract Polygon_Adapter is AdapterInterface {\\r\\n using SafeERC20 for IERC20;\\r\\n IRootChainManager public immutable rootChainManager;\\r\\n IFxStateSender public immutable fxStateSender;\\r\\n DepositManager public immutable depositManager;\\r\\n address public immutable erc20Predicate;\\r\\n address public immutable l1Matic;\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n /**\\r\\n * @notice Constructs new Adapter.\\r\\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\\r\\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\\r\\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\\r\\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\\r\\n * @param _l1Matic matic address on l1.\\r\\n * @param _l1Weth WETH address on L1.\\r\\n */\\r\\n constructor(\\r\\n IRootChainManager _rootChainManager,\\r\\n IFxStateSender _fxStateSender,\\r\\n DepositManager _depositManager,\\r\\n address _erc20Predicate,\\r\\n address _l1Matic,\\r\\n WETH9 _l1Weth\\r\\n ) {\\r\\n rootChainManager = _rootChainManager;\\r\\n fxStateSender = _fxStateSender;\\r\\n depositManager = _depositManager;\\r\\n erc20Predicate = _erc20Predicate;\\r\\n l1Matic = _l1Matic;\\r\\n l1Weth = _l1Weth;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Send cross-chain message to target on Polygon.\\r\\n * @param target Contract on Polygon that will receive message.\\r\\n * @param message Data to send to target.\\r\\n */\\r\\n\\r\\n function relayMessage(address target, bytes calldata message) external payable override {\\r\\n fxStateSender.sendMessageToChild(target, message);\\r\\n emit MessageRelayed(target, message);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Bridge tokens to Polygon.\\r\\n * @param l1Token L1 token to deposit.\\r\\n * @param l2Token L2 token to receive.\\r\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\r\\n * @param to Bridge recipient.\\r\\n */\\r\\n function relayTokens(\\r\\n address l1Token,\\r\\n address l2Token,\\r\\n uint256 amount,\\r\\n address to\\r\\n ) external payable override {\\r\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\r\\n if (l1Token == address(l1Weth)) {\\r\\n l1Weth.withdraw(amount);\\r\\n rootChainManager.depositEtherFor{ value: amount }(to);\\r\\n } else if (l1Token == l1Matic) {\\r\\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\\r\\n depositManager.depositERC20ForUser(l1Token, to, amount);\\r\\n } else {\\r\\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\\r\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\r\\n }\\r\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xac06498e0b896c0365fe8410417d10bcc02a4de509a3b815b43cc5e48d91552d\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6101406040523480156200001257600080fd5b50604051620010193803806200101983398101604081905262000035916200007e565b6001600160a01b0395861660805293851660a05291841660c052831660e052821661010052166101205262000112565b6001600160a01b03811681146200007b57600080fd5b50565b60008060008060008060c087890312156200009857600080fd5b8651620000a58162000065565b6020880151909650620000b88162000065565b6040880151909550620000cb8162000065565b6060880151909450620000de8162000065565b6080880151909350620000f18162000065565b60a0880151909250620001048162000065565b809150509295509295509295565b60805160a05160c05160e0516101005161012051610e79620001a06000396000818160920152818161020b015261028b01526000818161016c01526103a60152600081816101a0015261050901526000818161010401528181610413015261048c01526000818161013801526106810152600081816101d40152818161033f01526105300152610e796000f3fe60806040526004361061007b5760003560e01c8063b28de9e81161004e578063b28de9e81461015a578063b68649761461018e578063bd07018d146101c2578063e6eb8ade146101f657600080fd5b8063146bf4b11461008057806352c8c75c146100dd5780636c7ac9d8146100f2578063a996cabb14610126575b600080fd5b34801561008c57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100f06100eb366004610ba8565b610209565b005b3480156100fe57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561013257600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561016657600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561019a57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b6100f0610204366004610bf5565b610644565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103a4576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156102e457600080fd5b505af11580156102f8573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b15801561038657600080fd5b505af115801561039a573d6000803e3d6000fd5b50505050506105df565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036104ed5761043873ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b6040517f8b9e4f9300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528281166024830152604482018490527f00000000000000000000000000000000000000000000000000000000000000001690638b9e4f9390606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b505050506105df565b61052e73ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161057f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016105ac93929190610cee565b600060405180830381600087803b1580156105c657600080fd5b505af11580156105da573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906106ba90869086908690600401610d30565b600060405180830381600087803b1580156106d457600080fd5b505af11580156106e8573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161071f93929190610d30565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c79190610d9a565b6107d19190610db3565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610861908590610867565b50505050565b60006108c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661097d9092919063ffffffff16565b80519091501561097857808060200190518101906108e79190610df2565b610978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061098c8484600085610996565b90505b9392505050565b606082471015610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161096f565b73ffffffffffffffffffffffffffffffffffffffff85163b610aa6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161096f565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610acf9190610e14565b60006040518083038185875af1925050503d8060008114610b0c576040519150601f19603f3d011682016040523d82523d6000602084013e610b11565b606091505b5091509150610b21828286610b2c565b979650505050505050565b60608315610b3b57508161098f565b825115610b4b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096f9190610e30565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ba357600080fd5b919050565b60008060008060808587031215610bbe57600080fd5b610bc785610b7f565b9350610bd560208601610b7f565b925060408501359150610bea60608601610b7f565b905092959194509250565b600080600060408486031215610c0a57600080fd5b610c1384610b7f565b9250602084013567ffffffffffffffff80821115610c3057600080fd5b818601915086601f830112610c4457600080fd5b813581811115610c5357600080fd5b876020828501011115610c6557600080fd5b6020830194508093505050509250925092565b60005b83811015610c93578181015183820152602001610c7b565b838111156108615750506000910152565b60008151808452610cbc816020860160208601610c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610d276060830184610ca4565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600060208284031215610dac57600080fd5b5051919050565b60008219821115610ded577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610e0457600080fd5b8151801515811461098f57600080fd5b60008251610e26818460208701610c78565b9190910192915050565b60208152600061098f6020830184610ca456fea264697066735822122006c8302b81644d77ec414a1fdc181ef1d45419b0403f705415ee193f8aff341764736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061007b5760003560e01c8063b28de9e81161004e578063b28de9e81461015a578063b68649761461018e578063bd07018d146101c2578063e6eb8ade146101f657600080fd5b8063146bf4b11461008057806352c8c75c146100dd5780636c7ac9d8146100f2578063a996cabb14610126575b600080fd5b34801561008c57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100f06100eb366004610ba8565b610209565b005b3480156100fe57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561013257600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561016657600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b34801561019a57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b3480156101ce57600080fd5b506100b47f000000000000000000000000000000000000000000000000000000000000000081565b6100f0610204366004610bf5565b610644565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103a4576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156102e457600080fd5b505af11580156102f8573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b15801561038657600080fd5b505af115801561039a573d6000803e3d6000fd5b50505050506105df565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036104ed5761043873ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b6040517f8b9e4f9300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528281166024830152604482018490527f00000000000000000000000000000000000000000000000000000000000000001690638b9e4f9390606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b505050506105df565b61052e73ffffffffffffffffffffffffffffffffffffffff85167f00000000000000000000000000000000000000000000000000000000000000008461072c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161057f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016105ac93929190610cee565b600060405180830381600087803b1580156105c657600080fd5b505af11580156105da573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906106ba90869086908690600401610d30565b600060405180830381600087803b1580156106d457600080fd5b505af11580156106e8573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac483838360405161071f93929190610d30565b60405180910390a1505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c79190610d9a565b6107d19190610db3565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610861908590610867565b50505050565b60006108c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661097d9092919063ffffffff16565b80519091501561097857808060200190518101906108e79190610df2565b610978576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b606061098c8484600085610996565b90505b9392505050565b606082471015610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161096f565b73ffffffffffffffffffffffffffffffffffffffff85163b610aa6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161096f565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610acf9190610e14565b60006040518083038185875af1925050503d8060008114610b0c576040519150601f19603f3d011682016040523d82523d6000602084013e610b11565b606091505b5091509150610b21828286610b2c565b979650505050505050565b60608315610b3b57508161098f565b825115610b4b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096f9190610e30565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ba357600080fd5b919050565b60008060008060808587031215610bbe57600080fd5b610bc785610b7f565b9350610bd560208601610b7f565b925060408501359150610bea60608601610b7f565b905092959194509250565b600080600060408486031215610c0a57600080fd5b610c1384610b7f565b9250602084013567ffffffffffffffff80821115610c3057600080fd5b818601915086601f830112610c4457600080fd5b813581811115610c5357600080fd5b876020828501011115610c6557600080fd5b6020830194508093505050509250925092565b60005b83811015610c93578181015183820152602001610c7b565b838111156108615750506000910152565b60008151808452610cbc816020860160208601610c78565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610d276060830184610ca4565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b600060208284031215610dac57600080fd5b5051919050565b60008219821115610ded577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610e0457600080fd5b8151801515811461098f57600080fd5b60008251610e26818460208701610c78565b9190910192915050565b60208152600061098f6020830184610ca456fea264697066735822122006c8302b81644d77ec414a1fdc181ef1d45419b0403f705415ee193f8aff341764736f6c634300080d0033", "devdoc": { diff --git a/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json b/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json index 638f2fec..9c65fe4f 100644 --- a/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json +++ b/deployments/mainnet/solcInputs/2433465a1be70a13b6719df6fea2831a.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json b/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json index f9b52656..8192e2d9 100644 --- a/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json +++ b/deployments/mainnet/solcInputs/375f3de1549a735f4b746d114c8a6633.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Contract is paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Enables the owner of the protocol to haircut reserves in the event of an irrecoverable loss of funds on\r\n * one of the L2s. Consider funds are leant out onto a L2 that dies irrecoverably. This value will offset the\r\n * exchangeRateCurrent such that all LPs receive a pro rata loss of the the reserves. Should be used in conjunction\r\n * with pause logic to prevent LPs from adding/withdrawing liquidity during the haircut process.\r\n * Callable only by owner.\r\n * @param l1Token Token to execute the haircut on.\r\n * @param haircutAmount The amount of reserves to haircut the LPs by.\r\n */\r\n function haircutReserves(address l1Token, int256 haircutAmount) public onlyOwner nonReentrant {\r\n // Note that we do not call sync first in this method. The Owner should call this manually before haircutting.\r\n // This is done in the event sync is reverting due to too low balanced in the contract relative to bond amount.\r\n pooledTokens[l1Token].utilizedReserves -= haircutAmount;\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant unpaused {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant unpaused {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Contract is paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Enables the owner of the protocol to haircut reserves in the event of an irrecoverable loss of funds on\r\n * one of the L2s. Consider funds are leant out onto a L2 that dies irrecoverably. This value will offset the\r\n * exchangeRateCurrent such that all LPs receive a pro rata loss of the the reserves. Should be used in conjunction\r\n * with pause logic to prevent LPs from adding/withdrawing liquidity during the haircut process.\r\n * Callable only by owner.\r\n * @param l1Token Token to execute the haircut on.\r\n * @param haircutAmount The amount of reserves to haircut the LPs by.\r\n */\r\n function haircutReserves(address l1Token, int256 haircutAmount) public onlyOwner nonReentrant {\r\n // Note that we do not call sync first in this method. The Owner should call this manually before haircutting.\r\n // This is done in the event sync is reverting due to too low balanced in the contract relative to bond amount.\r\n pooledTokens[l1Token].utilizedReserves -= haircutAmount;\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant unpaused {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant unpaused {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 43633ef5..9303e25d 100644 --- a/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/mainnet/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json b/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json index f5967914..a86e6ce1 100644 --- a/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json +++ b/deployments/mainnet/solcInputs/778ed9956c3f76e793496228f16e1373.json @@ -2,28 +2,28 @@ "language": "Solidity", "sources": { "contracts/Succinct_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./external/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be misinterpreted.\n // Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(\n msg.sender == succinctTargetAmb && _senderAddress == hubPool && _sourceChainId == hubChainId,\n \"Invalid message\"\n );\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./external/SuccinctInterfaces.sol\";\n\n/**\n * @notice Succinct Spoke pool.\n */\ncontract Succinct_SpokePool is SpokePool, ITelepathyHandler {\n // Address of the succinct AMB contract.\n address public succinctTargetAmb;\n\n // Chain where HubPool is deployed that is linked to this SpokePool.\n uint16 public hubChainId;\n\n // Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be\n // private. Leaving it set to true can permanently disable admin calls.\n bool private adminCallValidated;\n\n // Note: validating calls this way ensures that strange calls coming from the succinctTargetAmb won't be misinterpreted.\n // Put differently, just checking that msg.sender == succinctTargetAmb is not sufficient.\n // All calls that have admin privileges must be fired from within the handleTelepathy method that's gone\n // through validation where the sender is checked and the sender from the other chain is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!adminCallValidated, \"adminCallValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed.\n adminCallValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n adminCallValidated = false;\n }\n\n /**\n * @notice Construct the Succinct SpokePool.\n * @param _hubChainId Chain ID of the chain where the HubPool is deployed.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeToken Address of the wrapped native token.\n */\n function initialize(\n uint16 _hubChainId,\n address _succinctTargetAmb,\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeToken\n ) public initializer {\n __SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken);\n succinctTargetAmb = _succinctTargetAmb;\n hubChainId = _hubChainId;\n }\n\n /**\n * @notice Admin can reset the succinct contract address.\n * @param _succinctTargetAmb Address of the succinct AMB contract.\n */\n function setSuccinctTargetAmb(address _succinctTargetAmb) external onlyAdmin {\n succinctTargetAmb = _succinctTargetAmb;\n }\n\n /**\n * @notice This will be called by Succinct AMB on this network to relay a message sent from the HubPool.\n * @param _sourceChainId Chain ID of the chain where the message originated.\n * @param _senderAddress Address of the sender on the chain where the message originated.\n * @param _data Data to be received and executed on this contract.\n */\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external override validateInternalCalls returns (bytes4) {\n // Validate msg.sender as succinct, the x-chain sender as being the hubPool (the admin) and the source chain as\n // 1 (mainnet).\n require(\n msg.sender == succinctTargetAmb && _senderAddress == hubPool && _sourceChainId == hubChainId,\n \"Invalid message\"\n );\n\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, ) = address(this).delegatecall(_data);\n require(success, \"delegatecall failed\");\n return ITelepathyHandler.handleTelepathy.selector;\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory) internal override {\n // This method is a no-op. If the chain intends to include bridging functionality, this must be overriden.\n // If not, leaving this unimplemented means this method may be triggered, but the result will be that no\n // balance is transferred.\n }\n\n // Check that the handleTelepathy method has validated the method to ensure the sender is authenticated.\n function _requireAdminSender() internal view override {\n require(adminCallValidated, \"Admin call not validated\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 updatedRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n struct DepositUpdate {\n uint32 depositId;\n uint256 originChainId;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit and fill functions. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(updatedRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: amount,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (relayExecution.maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = relayExecution.maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Note: since _computeAmountPostFees is typicaly intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n }\n }\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n relayFills[relayExecution.relayHash] + fillAmountPreFees,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n uint256 endingFillAmount,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, it's an initial 0-fill, or a partial fill has already happened, do nothing, as these\n // should not impact the count.\n if (useContractFunds || endingFillAmount == 0 || startingFillAmount > 0) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo;\n // This separate struct is created entirely to avoid stack too deep errors.\n {\n relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n }\n\n {\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor,\n bytes memory message\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor,\n message\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9Interface.sol\";\nimport \"./SpokePoolInterface.sol\";\nimport \"./upgradeable/MultiCallerUpgradeable.sol\";\nimport \"./upgradeable/EIP712CrossChainUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\n\n// This interface is expected to be implemented by any contract that expects to recieve messages from the SpokePool.\ninterface AcrossMessageHandler {\n function handleAcrossMessage(\n address tokenSent,\n uint256 amount,\n bytes memory message\n ) external;\n}\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is\n SpokePoolInterface,\n UUPSUpgradeable,\n ReentrancyGuardUpgradeable,\n MultiCallerUpgradeable,\n EIP712CrossChainUpgradeable\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using AddressUpgradeable for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. This should normally be set to the HubPool\n // address. The crossDomainAdmin address is unused when the SpokePool is deployed to the same chain as the HubPool.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9Interface public wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 1 hour.\n uint32 public depositQuoteTimeBuffer;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Whether deposits and fills are disabled.\n bool public pausedFills;\n bool public pausedDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n // This keeps track of the worst-case liabilities due to fills.\n // It is never reset. Users should only rely on it to determine the worst-case increase in liabilities between\n // two points. This is used to provide frontrunning protection to ensure the relayer's assumptions about the state\n // upon which their expected repayments are based will not change before their transaction is mined.\n mapping(address => uint256) public fillCounter;\n\n // This keeps track of the total running deposits for each token. This allows depositors to protect themselves from\n // frontrunning that might change their worst-case quote.\n mapping(address => uint256) public depositCounter;\n\n uint256 public constant MAX_TRANSFER_SIZE = 1e36;\n\n bytes32 public constant UPDATE_DEPOSIT_DETAILS_HASH =\n keccak256(\n \"UpdateDepositDetails(uint32 depositId,uint256 originChainId,int64 updatedRelayerFeePct,address updatedRecipient,bytes updatedMessage)\"\n );\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor,\n bytes message\n );\n event RequestedSpeedUpDeposit(\n int64 updatedRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n int64 realizedLpFeePct,\n uint32 indexed depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bytes message,\n RelayExecutionInfo updatableRelayData\n );\n\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n event PausedDeposits(bool isPaused);\n event PausedFills(bool isPaused);\n\n struct RelayExecution {\n RelayData relay;\n bytes32 relayHash;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n uint256 maxTokensToSend;\n uint256 maxCount;\n bool slowFill;\n int256 payoutAdjustmentPct;\n }\n\n struct RelayExecutionInfo {\n address recipient;\n bytes message;\n int64 relayerFeePct;\n bool isSlowRelay;\n int256 payoutAdjustmentPct;\n }\n\n struct DepositUpdate {\n uint32 depositId;\n uint256 originChainId;\n int64 updatedRelayerFeePct;\n address updatedRecipient;\n bytes updatedMessage;\n }\n\n /**\n * Do not leave an implementation contract uninitialized. An uninitialized implementation contract can be\n * taken over by an attacker, which may impact the proxy. To prevent the implementation contract from being\n * used, you should invoke the _disableInitializers function in the constructor to automatically lock it when\n * it is deployed:\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Construct the base SpokePool.\n * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate\n * relay hash collisions.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n */\n function __SpokePool_init(\n uint32 _initialDepositId,\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress\n ) public onlyInitializing {\n numberOfDeposits = _initialDepositId;\n __EIP712_init(\"ACROSS-V2\", \"1.0.0\");\n __UUPSUpgradeable_init();\n __ReentrancyGuard_init();\n depositQuoteTimeBuffer = 3600;\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9Interface(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n * @dev This should be set to cross domain admin for specific SpokePool.\n */\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n modifier unpausedDeposits() {\n require(!pausedDeposits, \"Paused deposits\");\n _;\n }\n\n modifier unpausedFills() {\n require(!pausedFills, \"Paused fills\");\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n // Allows cross domain admin to upgrade UUPS proxy implementation.\n function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}\n\n /**\n * @notice Pauses deposit and fill functions. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function pauseDeposits(bool pause) public override onlyAdmin nonReentrant {\n pausedDeposits = pause;\n emit PausedDeposits(pause);\n }\n\n function pauseFills(bool pause) public override onlyAdmin nonReentrant {\n pausedFills = pause;\n emit PausedFills(pause);\n }\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n // Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's\n // data will still remain potentially leading to vulnerabilities down the line. The way around this would\n // be to iterate through every key in the mapping and resetting the value to 0, but this seems expensive and\n // would require a new list in storage to keep track of keys.\n //slither-disable-next-line mapping-deletion\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) public payable override nonReentrant unpausedDeposits {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(SignedMath.abs(relayerFeePct) < 0.5e18, \"Invalid relayer fee\");\n require(amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n require(depositCounter[originToken] <= maxCount, \"Above max count\");\n\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n\n //slither-disable-next-line timestamp\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n uint32 newDepositId = numberOfDeposits++;\n depositCounter[originToken] += amount;\n\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20Upgradeable(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n newDepositId,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender,\n message\n );\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @notice This function is not subject to a deposit pause on the off chance that deposits sent before all deposits\n * are paused have very low fees and the user wants to entice a relayer to fill them with a higher fee.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param updatedRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param updatedRecipient New recipient address that should receive the tokens.\n * @param updatedMessage New message that should be provided to the recipient.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(updatedRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n chainId(),\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(\n updatedRelayerFeePct,\n depositId,\n depositor,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Message to send to recipient along with tokens.\n * @param maxCount Max count to protect the relayer from frontrunning.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) public nonReentrant unpausedFills {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: relayerFeePct,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param updatedRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param message Original message that was sent along with this deposit.\n * @param updatedMessage Modified message that the depositor signed when updating parameters.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-712 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n * @param maxCount Max fill count to protect the relayer from frontrunning.\n */\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) public override nonReentrant unpausedFills {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId(),\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: updatedRelayerFeePct,\n updatedRecipient: updatedRecipient,\n updatedMessage: updatedMessage,\n repaymentChainId: repaymentChainId,\n maxTokensToSend: maxTokensToSend,\n slowFill: false,\n payoutAdjustmentPct: 0,\n maxCount: maxCount\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifyUpdateDepositMessage(\n depositor,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n updatedMessage,\n depositorSignature\n );\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param message Message to send to the recipient if the recipient is a contract.\n * @param payoutAdjustment Adjustment to the payout amount. Can be used to increase or decrease the payout to allow\n * for rewards or penalties.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n message,\n payoutAdjustment,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**\n * @notice Gets the current time.\n * @return uint for the current timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20Upgradeable(relayerRefundLeaf.l2TokenAddress).safeTransfer(\n relayerRefundLeaf.refundAddresses[i],\n amount\n );\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustmentPct,\n bytes32[] memory proof\n ) internal {\n RelayExecution memory relayExecution = RelayExecution({\n relay: SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n message: message\n }),\n relayHash: bytes32(0),\n updatedRelayerFeePct: 0,\n updatedRecipient: recipient,\n updatedMessage: message,\n repaymentChainId: 0,\n maxTokensToSend: amount,\n slowFill: true,\n payoutAdjustmentPct: payoutAdjustmentPct,\n maxCount: type(uint256).max\n });\n relayExecution.relayHash = _getRelayHash(relayExecution.relay);\n\n _verifySlowFill(relayExecution, rootBundleId, proof);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayExecution);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayExecution, fillAmountPreFees);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateDepositMessage(\n address depositor,\n uint32 depositId,\n uint256 originChainId,\n int64 updatedRelayerFeePct,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to modify an un-relayed deposit by signing a hash containing the updated\n // details and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits.\n // Note: We use the EIP-712 (https://eips.ethereum.org/EIPS/eip-712) standard for hashing and signing typed data.\n // Specifically, we use the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n // `eth_signedTypedDataV4` in MetaMask (https://docs.metamask.io/guide/signing-data.html).\n bytes32 expectedTypedDataV4Hash = _hashTypedDataV4(\n // EIP-712 compliant hash struct: https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct\n keccak256(\n abi.encode(\n UPDATE_DEPOSIT_DETAILS_HASH,\n depositId,\n originChainId,\n updatedRelayerFeePct,\n updatedRecipient,\n keccak256(updatedMessage)\n )\n ),\n // By passing in the origin chain id, we enable the verification of the signature on a different chain\n originChainId\n );\n _verifyDepositorSignature(depositor, expectedTypedDataV4Hash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorSignature(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note:\n // - We don't need to worry about reentrancy from a contract deployed at the depositor address since the method\n // `SignatureChecker.isValidSignatureNow` is a view method. Re-entrancy can happen, but it cannot affect state.\n // - EIP-1271 signatures are supported. This means that a signature valid now, may not be valid later and vice-versa.\n // - For an EIP-1271 signature to work, the depositor contract address must map to a deployed contract on the destination\n // chain that can validate the signature.\n // - Regular signatures from an EOA are also supported.\n bool isValid = SignatureChecker.isValidSignatureNow(depositor, ethSignedMessageHash, depositorSignature);\n require(isValid, \"invalid signature\");\n }\n\n function _verifySlowFill(\n RelayExecution memory relayExecution,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal view {\n SlowFill memory slowFill = SlowFill({\n relayData: relayExecution.relay,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, slowFill, proof),\n \"Invalid slow relay proof\"\n );\n }\n\n function _computeAmountPreFees(uint256 amount, int64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / uint256((int256(1e18) - feesPct));\n }\n\n function _computeAmountPostFees(uint256 amount, int256 feesPct) private pure returns (uint256) {\n return (amount * uint256(int256(1e18) - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20Upgradeable(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n //slither-disable-next-line arbitrary-send-eth\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(RelayExecution memory relayExecution) internal returns (uint256 fillAmountPreFees) {\n RelayData memory relayData = relayExecution.relay;\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(\n SignedMath.abs(relayExecution.updatedRelayerFeePct) < 0.5e18 &&\n SignedMath.abs(relayData.realizedLpFeePct) < 0.5e18,\n \"invalid fees\"\n );\n\n require(relayData.amount <= MAX_TRANSFER_SIZE, \"Amount too large\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayExecution.relayHash] < relayData.amount, \"relay filled\");\n\n // This allows the caller to add in frontrunning protection for quote validity.\n require(fillCounter[relayData.destinationToken] <= relayExecution.maxCount, \"Above max count\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (relayExecution.maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n relayExecution.maxTokensToSend,\n (relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = relayExecution.maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayExecution.relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + relayExecution.updatedRelayerFeePct\n );\n\n if (relayExecution.payoutAdjustmentPct != 0) {\n // If payoutAdjustmentPct is positive, then the recipient will receive more than the amount they\n // were originally expecting. If it is negative, then the recipient will receive less.\n // -1e18 is -100%. Because we cannot pay out negative values, that is the minimum.\n require(relayExecution.payoutAdjustmentPct >= -1e18, \"payoutAdjustmentPct too small\");\n\n // Note: since _computeAmountPostFees is typicaly intended for fees, the signage must be reversed.\n amountToSend = _computeAmountPostFees(amountToSend, -relayExecution.payoutAdjustmentPct);\n }\n }\n\n // Update fill counter.\n _updateCountFromFill(\n relayFills[relayExecution.relayHash],\n relayFills[relayExecution.relayHash] + fillAmountPreFees,\n relayData.amount,\n relayData.realizedLpFeePct,\n relayData.destinationToken,\n relayExecution.slowFill\n );\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayExecution.relayHash] += fillAmountPreFees;\n\n // If relayer and receiver are the same address, there is no need to do any transfer, as it would result in no\n // net movement of funds.\n // Note: this is important because it means that relayers can intentionally self-relay in a capital efficient\n // way (no need to have funds on the destination).\n if (msg.sender == relayData.recipient) return fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!relayExecution.slowFill)\n IERC20Upgradeable(relayData.destinationToken).safeTransferFrom(\n msg.sender,\n relayData.recipient,\n amountToSend\n );\n else IERC20Upgradeable(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n\n if (relayData.recipient.isContract() && relayData.message.length > 0) {\n AcrossMessageHandler(relayData.recipient).handleAcrossMessage(\n relayData.destinationToken,\n amountToSend,\n relayData.message\n );\n }\n }\n\n function _updateCountFromFill(\n uint256 startingFillAmount,\n uint256 endingFillAmount,\n uint256 totalFillAmount,\n int64 realizedLPFeePct,\n address token,\n bool useContractFunds\n ) internal {\n // If this is a slow fill, it's an initial 0-fill, or a partial fill has already happened, do nothing, as these\n // should not impact the count.\n if (useContractFunds || endingFillAmount == 0 || startingFillAmount > 0) return;\n fillCounter[token] += _computeAmountPostFees(totalFillAmount, realizedLPFeePct);\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(RelayExecution memory relayExecution, uint256 fillAmountPreFees) internal {\n RelayExecutionInfo memory relayExecutionInfo;\n // This separate struct is created entirely to avoid stack too deep errors.\n {\n relayExecutionInfo = RelayExecutionInfo({\n relayerFeePct: relayExecution.updatedRelayerFeePct,\n recipient: relayExecution.updatedRecipient,\n message: relayExecution.updatedMessage,\n isSlowRelay: relayExecution.slowFill,\n payoutAdjustmentPct: relayExecution.payoutAdjustmentPct\n });\n }\n\n {\n emit FilledRelay(\n relayExecution.relay.amount,\n relayFills[relayExecution.relayHash],\n fillAmountPreFees,\n relayExecution.repaymentChainId,\n relayExecution.relay.originChainId,\n relayExecution.relay.destinationChainId,\n relayExecution.relay.relayerFeePct,\n relayExecution.relay.realizedLpFeePct,\n relayExecution.relay.depositId,\n relayExecution.relay.destinationToken,\n msg.sender,\n relayExecution.relay.depositor,\n relayExecution.relay.recipient,\n relayExecution.relay.message,\n relayExecutionInfo\n );\n }\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor,\n bytes memory message\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor,\n message\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/interfaces/WETH9Interface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9Interface {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9Interface {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external returns (bool);\n}\n" }, "contracts/external/SuccinctInterfaces.sol": { "content": "pragma solidity ^0.8.0;\n\n// These interfaces are a subset of the Succinct interfaces here: https://github.com/succinctlabs/telepathy-contracts.\n\n// This interface should be implemented by any contract wanting to receive messages sent over the Succinct bridge.\ninterface ITelepathyHandler {\n function handleTelepathy(\n uint16 _sourceChainId,\n address _senderAddress,\n bytes memory _data\n ) external returns (bytes4);\n}\n\n// This interface represents the contract that we call into to send messages over the Succinct AMB.\ninterface ITelepathyBroadcaster {\n function send(\n uint16 _recipientChainId,\n address _recipientAddress,\n bytes calldata _data\n ) external returns (bytes32);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.SlowFill memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n int64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n int64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n struct SlowFill {\n RelayData relayData;\n int256 payoutAdjustmentPct;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function pauseDeposits(bool pause) external;\n\n function pauseFills(bool pause) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n int64 relayerFeePct,\n uint32 quoteTimestamp,\n bytes memory message,\n uint256 maxCount\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n address updatedRecipient,\n bytes memory updatedMessage,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n bytes memory message,\n uint256 maxCount\n ) external;\n\n function fillRelayWithUpdatedDeposit(\n address depositor,\n address recipient,\n address updatedRecipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n int64 updatedRelayerFeePct,\n uint32 depositId,\n bytes memory message,\n bytes memory updatedMessage,\n bytes memory depositorSignature,\n uint256 maxCount\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n int64 realizedLpFeePct,\n int64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes memory message,\n int256 payoutAdjustment,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/upgradeable/MultiCallerUpgradeable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title MockSpokePool\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title MockSpokePool\n * @notice Logic is 100% copied from \"@uma/core/contracts/common/implementation/MultiCaller.sol\" but one\n * comment is added to clarify why we allow delegatecall() in this contract, which is typically unsafe for use in\n * upgradeable implementation contracts.\n * @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/faq#delegatecall-selfdestruct for more details.\n */\ncontract MultiCallerUpgradeable {\n function multicall(bytes[] calldata data) external returns (bytes[] memory results) {\n results = new bytes[](data.length);\n\n //slither-disable-start calls-loop\n for (uint256 i = 0; i < data.length; i++) {\n // Typically, implementation contracts used in the upgradeable proxy pattern shouldn't call `delegatecall`\n // because it could allow a malicious actor to call this implementation contract directly (rather than\n // through a proxy contract) and then selfdestruct() the contract, thereby freezing the upgradeable\n // proxy. However, since we're only delegatecall-ing into this contract, then we can consider this\n // use of delegatecall() safe.\n\n //slither-disable-start low-level-calls\n /// @custom:oz-upgrades-unsafe-allow delegatecall\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n //slither-disable-end low-level-calls\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n //slither-disable-next-line assembly\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n //slither-disable-end calls-loop\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "contracts/upgradeable/EIP712CrossChainUpgradeable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * This contract is based on OpenZeppelin's implementation:\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol\n *\n * NOTE: Modified version that allows to build a domain separator that relies on a different chain id than the chain this\n * contract is deployed to. An example use case we want to support is:\n * - User A signs a message on chain with id = 1\n * - User B executes a method by verifying user A's EIP-712 compliant signature on a chain with id != 1\n */\nabstract contract EIP712CrossChainUpgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator depending on the `originChainId`.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 EIP-712-compliant domain separator.\n */\n function _domainSeparatorV4(uint256 originChainId) internal view returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, originChainId));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 structHash = keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * ));\n * bytes32 digest = _hashTypedDataV4(structHash, originChainId);\n * address signer = ECDSA.recover(digest, signature);\n * ```\n * @param structHash Hashed struct as defined in https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.\n * @param originChainId Chain id of network where message originates from.\n * @return bytes32 Hash digest that is recoverable via `EDCSA.recover`.\n */\n function _hashTypedDataV4(bytes32 structHash, uint256 originChainId) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(originChainId), structHash);\n }\n\n // Reserve storage slots for future versions of this base contract to add state variables without\n // affecting the storage layout of child contracts. Decrement the size of __gap whenever state variables\n // are added. This is at bottom of contract to make sure its always at the end of storage.\n uint256[1000] private __gap;\n}\n" }, "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" @@ -50,13 +50,13 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n function safeTransfer(\n IERC20Upgradeable token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20Upgradeable token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20Upgradeable token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/token/ERC20/IERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" @@ -98,10 +98,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" diff --git a/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json b/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json index 537422d6..443a80d8 100644 --- a/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json +++ b/deployments/mainnet/solcInputs/80d9895099d6448454133a653020a62d.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,43 +113,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -158,22 +158,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json b/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json index 206a1490..0243bee8 100644 --- a/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json +++ b/deployments/mainnet/solcInputs/9ecc79ca0809d14763bad8554b06546b.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n function createRetryableTicketNoRefundAliasRewrite(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n function createRetryableTicketNoRefundAliasRewrite(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n // Note: we use the unsafe version of createRetryableTicket because it doesn't require the msg.sender to pass\n // in arbTxCallValue in addition to maxSubmissionCost + maxGas * gasPriceBid.\n l1Inbox.createRetryableTicketNoRefundAliasRewrite{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json b/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json index e4367cfe..9a0dc4f6 100644 --- a/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json +++ b/deployments/mainnet/solcInputs/a254ea7a050d78a978809e4c33fcb9ff.json @@ -2,13 +2,13 @@ "language": "Solidity", "sources": { "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport { ArbitrumL1ERC20GatewayLike } from \"./Arbitrum_Adapter.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * RELAY_TOKENS_L2_GAS_LIMIT;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n\n function unsafeCreateRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI: the implementation of `outboundTransfer` at the current DAI custom gateway\n // (https://etherscan.io/address/0xD3B5b60020504bc3489D6949d545893982BA3011#writeContract) sets the\n // sender as the refund address so the aliased HubPool should receive excess funds. Implementation here:\n // https://github.com/makerdao/arbitrum-dai-bridge/blob/11a80385e2622968069c34d401b3d54a59060e87/contracts/l1/L1DaiGateway.sol#L109\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter, the Arbitrum_RescueAdapter.\n // To do so, in a single transaction: 1) setCrossChainContracts to Arbitrum_RescueAdapter, 2) relayMessage\n // with function data = abi.encode(amountToRescue), 3) setCrossChainContracts back to this adapter.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/IERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" diff --git a/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json b/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json index d8174d10..d2f1997a 100644 --- a/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json +++ b/deployments/mainnet/solcInputs/aa94850b4a0bee17111a41299cfa0033.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -14,7 +14,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./MerkleDistributorInterface.sol\";\n\n/**\n * Inspired by:\n * - https://github.com/pie-dao/vested-token-migration-app\n * - https://github.com/Uniswap/merkle-distributor\n * - https://github.com/balancer-labs/erc20-redeemable\n *\n * @title MerkleDistributor contract.\n * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify\n * multiple Merkle roots distributions with customized reward currencies.\n * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly.\n */\ncontract MerkleDistributor is MerkleDistributorInterface, Ownable {\n using SafeERC20 for IERC20;\n\n // Windows are mapped to arbitrary indices.\n mapping(uint256 => Window) public merkleWindows;\n\n // Index of next created Merkle root.\n uint256 public nextCreatedIndex;\n\n // Track which accounts have claimed for each window index.\n // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract.\n mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap;\n\n /****************************************\n * EVENTS\n ****************************************/\n event Claimed(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n event CreatedWindow(\n uint256 indexed windowIndex,\n uint256 rewardsDeposited,\n address indexed rewardToken,\n address owner\n );\n event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency);\n event DeleteWindow(uint256 indexed windowIndex, address owner);\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Set merkle root for the next available window index and seed allocations.\n * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer\n * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the\n * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all\n * claims within the `merkleRoot`.\n * @param rewardsToDeposit amount of rewards to deposit to seed this allocation.\n * @param rewardToken ERC20 reward token.\n * @param merkleRoot merkle root describing allocation.\n * @param ipfsHash hash of IPFS object, conveniently stored for clients\n */\n function setWindow(\n uint256 rewardsToDeposit,\n address rewardToken,\n bytes32 merkleRoot,\n string calldata ipfsHash\n ) external onlyOwner {\n uint256 indexToSet = nextCreatedIndex;\n nextCreatedIndex = indexToSet + 1;\n\n _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash);\n }\n\n /**\n * @notice Delete merkle root at window index.\n * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state.\n * @param windowIndex merkle root index to delete.\n */\n function deleteWindow(uint256 windowIndex) external onlyOwner {\n delete merkleWindows[windowIndex];\n emit DeleteWindow(windowIndex, msg.sender);\n }\n\n /**\n * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly.\n * @dev Callable only by owner.\n * @param rewardCurrency rewards to withdraw from contract.\n * @param amount amount of rewards to withdraw.\n */\n function withdrawRewards(IERC20 rewardCurrency, uint256 amount) external onlyOwner {\n rewardCurrency.safeTransfer(msg.sender, amount);\n emit WithdrawRewards(msg.sender, amount, address(rewardCurrency));\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev Optimistically tries to batch together consecutive claims for the same account and same\n * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method\n * is to pass in an array of claims sorted by account and reward currency. It also reverts\n * when any of individual `_claim`'s `amount` exceeds `remainingAmount` for its window.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public virtual override {\n uint256 batchedAmount;\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n Claim memory _claim = claims[i];\n _verifyAndMarkClaimed(_claim);\n batchedAmount += _claim.amount;\n\n // If the next claim is NOT the same account or the same token (or this claim is the last one),\n // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token.\n uint256 nextI = i + 1;\n IERC20 currentRewardToken = merkleWindows[_claim.windowIndex].rewardToken;\n if (\n nextI == claimCount ||\n // This claim is last claim.\n claims[nextI].account != _claim.account ||\n // Next claim account is different than current one.\n merkleWindows[claims[nextI].windowIndex].rewardToken != currentRewardToken\n // Next claim reward token is different than current one.\n ) {\n currentRewardToken.safeTransfer(_claim.account, batchedAmount);\n batchedAmount = 0;\n }\n }\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the\n * values stored in the merkle root for the `_claim`'s `windowIndex` this method\n * will revert. It also reverts when `_claim`'s `amount` exceeds `remainingAmount` for the window.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public virtual override {\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount);\n }\n\n /**\n * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at\n * `windowIndex`.\n * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`.\n * The onus is on the Owner of this contract to submit only valid Merkle roots.\n * @param windowIndex merkle root to check.\n * @param accountIndex account index to check within window index.\n * @return True if claim has been executed already, False otherwise.\n */\n function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Returns rewardToken set by admin for windowIndex.\n * @param windowIndex merkle root to check.\n * @return address Reward token address\n */\n function getRewardTokenForWindow(uint256 windowIndex) public view override returns (address) {\n return address(merkleWindows[windowIndex].rewardToken);\n }\n\n /**\n * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given\n * window index.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n * @return valid True if leaf exists.\n */\n function verifyClaim(Claim memory _claim) public view returns (bool valid) {\n bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex));\n return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf);\n }\n\n /****************************\n * PRIVATE FUNCTIONS\n ****************************/\n\n // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`.\n function _setClaimed(uint256 windowIndex, uint256 accountIndex) private {\n uint256 claimedWordIndex = accountIndex / 256;\n uint256 claimedBitIndex = accountIndex % 256;\n claimedBitMap[windowIndex][claimedWordIndex] =\n claimedBitMap[windowIndex][claimedWordIndex] |\n (1 << claimedBitIndex);\n }\n\n // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root.\n function _setWindow(\n uint256 windowIndex,\n uint256 rewardsDeposited,\n address rewardToken,\n bytes32 merkleRoot,\n string memory ipfsHash\n ) private {\n Window storage window = merkleWindows[windowIndex];\n window.merkleRoot = merkleRoot;\n window.remainingAmount = rewardsDeposited;\n window.rewardToken = IERC20(rewardToken);\n window.ipfsHash = ipfsHash;\n\n emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender);\n\n window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited);\n }\n\n // Verify claim is valid and mark it as completed in this contract.\n function _verifyAndMarkClaimed(Claim memory _claim) internal {\n // Check claimed proof against merkle window at given index.\n require(verifyClaim(_claim), \"Incorrect merkle proof\");\n // Check the account has not yet claimed for this window.\n require(!isClaimed(_claim.windowIndex, _claim.accountIndex), \"Account has already claimed for this window\");\n\n // Proof is correct and claim has not occurred yet, mark claimed complete.\n _setClaimed(_claim.windowIndex, _claim.accountIndex);\n merkleWindows[_claim.windowIndex].remainingAmount -= _claim.amount;\n emit Claimed(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -26,7 +26,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" }, "@uma/core/contracts/merkle-distributor/implementation/MerkleDistributorInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in MerkleDistributor implementation that would be called by\n * a consuming external contract (such as the Across Protocol's AcceleratingDistributor).\n */\ninterface MerkleDistributorInterface {\n // A Window maps a Merkle root to a reward token address.\n struct Window {\n // Merkle root describing the distribution.\n bytes32 merkleRoot;\n // Remaining amount of deposited rewards that have not yet been claimed.\n uint256 remainingAmount;\n // Currency in which reward is processed.\n IERC20 rewardToken;\n // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical\n // data type for storing an IPFS hash is a multihash which is the concatenation of \n // . We opted to store this in a string type to make it easier\n // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply\n // go to https://cloudflare-ipfs.com/ipfs/.\n string ipfsHash;\n }\n\n // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`.\n struct Claim {\n uint256 windowIndex;\n uint256 amount;\n uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim.\n address account;\n bytes32[] merkleProof;\n }\n\n function claim(Claim memory _claim) external;\n\n function claimMulti(Claim[] memory claims) external;\n\n function getRewardTokenForWindow(uint256 windowIndex) external view returns (address);\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" @@ -35,73 +35,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -116,13 +116,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -131,61 +131,61 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function outboundTransferCustomRefund(\n address _token,\n address _refundTo,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public constant l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public constant l2GasPrice = 5e9; // 5 gWei\n\n uint32 public constant RELAY_TOKENS_L2_GAS_LIMIT = 300_000;\n uint32 public constant RELAY_MESSAGE_L2_GAS_LIMIT = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public constant l2RefundL2Address = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_MESSAGE_L2_GAS_LIMIT);\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n RELAY_MESSAGE_L2_GAS_LIMIT, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance(RELAY_TOKENS_L2_GAS_LIMIT);\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: Legacy routers don't have the outboundTransferCustomRefund method, so default to using\n // outboundTransfer(). Legacy routers are used for the following tokens that are currently enabled:\n // - DAI\n if (l1Token == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2, which we'd have to retrieve via a custom adapter\n // (i.e. the Arbitrum_RescueAdapter).\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n } else {\n l1ERC20GatewayRouter.outboundTransferCustomRefund{ value: requiredL1CallValue }(\n l1Token,\n l2RefundL2Address,\n to,\n amount,\n RELAY_TOKENS_L2_GAS_LIMIT,\n l2GasPrice,\n data\n );\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue(uint32 l2GasLimit) public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance(uint32 l2GasLimit) internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue(l2GasLimit);\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/merkle-distributor/AcrossMerkleDistributor.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/merkle-distributor/implementation/MerkleDistributor.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Extended MerkleDistributor contract.\n * @notice Adds additional constraints governing who can claim leaves from merkle windows.\n */\ncontract AcrossMerkleDistributor is MerkleDistributor {\n using SafeERC20 for IERC20;\n\n // Addresses that can claim on user's behalf.\n mapping(address => bool) public whitelistedClaimers;\n\n /****************************************\n * EVENTS\n ****************************************/\n event WhitelistedClaimer(address indexed claimer, bool indexed whitelist);\n event ClaimFor(\n address indexed caller,\n uint256 windowIndex,\n address indexed account,\n uint256 accountIndex,\n uint256 amount,\n address indexed rewardToken\n );\n\n /****************************\n * ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Updates whitelisted claimer status.\n * @dev Callable only by owner.\n * @param newContract Reset claimer contract to this address.\n * @param whitelist True to whitelist claimer, False otherwise.\n */\n function whitelistClaimer(address newContract, bool whitelist) external onlyOwner {\n whitelistedClaimers[newContract] = whitelist;\n emit WhitelistedClaimer(newContract, whitelist);\n }\n\n /****************************\n * NON-ADMIN FUNCTIONS\n ****************************/\n\n /**\n * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail\n * if any individual claims within the batch would fail.\n * @dev All claim recipients must be equal to msg.sender.\n * @param claims array of claims to claim.\n */\n function claimMulti(Claim[] memory claims) public override {\n uint256 claimCount = claims.length;\n for (uint256 i = 0; i < claimCount; i++) {\n require(claims[i].account == msg.sender, \"invalid claimer\");\n }\n super.claimMulti(claims);\n }\n\n /**\n * @notice Claim amount of reward tokens for account, as described by Claim input object.\n * @dev Claim recipient must be equal to msg.sender.\n * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof.\n */\n function claim(Claim memory _claim) public override {\n require(_claim.account == msg.sender, \"invalid claimer\");\n super.claim(_claim);\n }\n\n /**\n * @notice Executes merkle leaf claim on behaf of user. This can only be called by a trusted\n * claimer address. This function is designed to be called atomically with other transactions\n * that ultimately return the claimed amount to the rightful recipient. For example,\n * AcceleratingDistributor could call this function and then stake atomically on behalf of the user.\n * @dev Caller must be in whitelistedClaimers struct set to \"true\".\n * @param _claim leaf to claim.\n */\n\n function claimFor(Claim memory _claim) public {\n require(whitelistedClaimers[msg.sender], \"unwhitelisted claimer\");\n _verifyAndMarkClaimed(_claim);\n merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(msg.sender, _claim.amount);\n emit ClaimFor(\n msg.sender,\n _claim.windowIndex,\n _claim.account,\n _claim.accountIndex,\n _claim.amount,\n address(merkleWindows[_claim.windowIndex].rewardToken)\n );\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n event RequestPrice(\n address indexed requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n address currency,\n uint256 reward,\n uint256 finalFee\n );\n event ProposePrice(\n address indexed requester,\n address indexed proposer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice,\n uint256 expirationTimestamp,\n address currency\n );\n event DisputePrice(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 proposedPrice\n );\n event Settle(\n address indexed requester,\n address indexed proposer,\n address indexed disputer,\n bytes32 identifier,\n uint256 timestamp,\n bytes ancillaryData,\n int256 price,\n uint256 payout\n );\n\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n function defaultLiveness() external view virtual returns (uint256);\n\n function finder() external view virtual returns (FinderInterface);\n\n function getCurrentTime() external view virtual returns (uint256);\n\n // Note: this is required so that typechain generates a return value with named fields.\n mapping(bytes32 => Request) public requests;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -194,22 +194,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant OptimisticOracleV2 = \"OptimisticOracleV2\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json b/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json index 5c9d5d01..4e7aab6e 100644 --- a/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json +++ b/deployments/mainnet/solcInputs/ac469a0c874627ad85d8b93b55e7f3fc.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\r\n */\r\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\r\n {}\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\r\n */\r\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\r\n {}\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json b/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json index a9377e90..74e62cf1 100644 --- a/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json +++ b/deployments/mainnet/solcInputs/b20d5afcf396996ae08652b8281973a7.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index a0cc1d52..2a6425e5 100644 --- a/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/mainnet/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json b/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json index 52e7ecd2..08c3cc5c 100644 --- a/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json +++ b/deployments/mainnet/solcInputs/f654478e897007c7ba14581b070ec005.json @@ -2,49 +2,49 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./HubPoolInterface.sol\";\r\nimport \"./Lockable.sol\";\r\n\r\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\r\n\r\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\r\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\r\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\r\n\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\r\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\r\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\r\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\r\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\r\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\r\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\r\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\r\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\r\n * disabled by the admin.\r\n */\r\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\r\n // can be submitted.\r\n RootBundle public rootBundleProposal;\r\n\r\n // Mapping of L1 token addresses to the associated pool information.\r\n mapping(address => PooledToken) public pooledTokens;\r\n\r\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\r\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\r\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\r\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\r\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\r\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\r\n mapping(bytes32 => address) private poolRebalanceRoutes;\r\n\r\n // Mapping of chainId to the associated adapter and spokePool contracts.\r\n mapping(uint256 => CrossChainContract) public crossChainContracts;\r\n\r\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\r\n\r\n // Whether the bundle proposal process is paused.\r\n bool public paused;\r\n\r\n // WETH contract for Ethereum.\r\n WETH9 public immutable weth;\r\n\r\n // Helper factory to deploy new LP tokens for enabled L1 tokens\r\n LpTokenFactoryInterface public immutable lpTokenFactory;\r\n\r\n // Finder contract for this network.\r\n FinderInterface public immutable finder;\r\n\r\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\r\n address public protocolFeeCaptureAddress;\r\n\r\n // Token used to bond the data worker for proposing relayer refund bundles.\r\n IERC20 public bondToken;\r\n\r\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\r\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\r\n uint32 public liveness = 7200;\r\n\r\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\r\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\r\n\r\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\r\n // the full amount of fees entitled to LPs in ~ 7.72 days assuming no contract interactions. If someone interacts\r\n // with the contract then the LP rewards are smeared sublinearly over the window (i.e spread over the remaining\r\n // period for each interaction which approximates a decreasing exponential function).\r\n uint256 public lpFeeRatePerSecond = 1500000000000;\r\n\r\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\r\n uint256 public protocolFeeCapturePct;\r\n\r\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\r\n uint256 public bondAmount;\r\n\r\n event Paused(bool indexed isPaused);\r\n\r\n event EmergencyRootBundleDeleted(\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n\r\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\r\n\r\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\r\n\r\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\r\n\r\n event LivenessSet(uint256 newLiveness);\r\n\r\n event IdentifierSet(bytes32 newIdentifier);\r\n\r\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\r\n\r\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\r\n\r\n event LiquidityAdded(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensMinted,\r\n address indexed liquidityProvider\r\n );\r\n event LiquidityRemoved(\r\n address indexed l1Token,\r\n uint256 amount,\r\n uint256 lpTokensBurnt,\r\n address indexed liquidityProvider\r\n );\r\n event SetPoolRebalanceRoute(\r\n uint256 indexed destinationChainId,\r\n address indexed l1Token,\r\n address indexed destinationToken\r\n );\r\n event SetEnableDepositRoute(\r\n uint256 indexed originChainId,\r\n uint256 indexed destinationChainId,\r\n address indexed originToken,\r\n bool depositsEnabled\r\n );\r\n event ProposeRootBundle(\r\n uint32 challengePeriodEndTimestamp,\r\n uint8 poolRebalanceLeafCount,\r\n uint256[] bundleEvaluationBlockNumbers,\r\n bytes32 indexed poolRebalanceRoot,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 slowRelayRoot,\r\n address indexed proposer\r\n );\r\n event RootBundleExecuted(\r\n uint256 groupIndex,\r\n uint256 indexed leafId,\r\n uint256 indexed chainId,\r\n address[] l1Tokens,\r\n uint256[] bundleLpFees,\r\n int256[] netSendAmounts,\r\n int256[] runningBalances,\r\n address indexed caller\r\n );\r\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\r\n\r\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\r\n\r\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\r\n\r\n modifier noActiveRequests() {\r\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\r\n _;\r\n }\r\n\r\n modifier unpaused() {\r\n require(!paused, \"Proposal process has been paused\");\r\n _;\r\n }\r\n\r\n modifier zeroOptimisticOracleApproval() {\r\n _;\r\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\r\n }\r\n\r\n /**\r\n * @notice Construct HubPool.\r\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\r\n * @param _finder Finder address.\r\n * @param _weth WETH address.\r\n * @param _timer Timer address.\r\n */\r\n constructor(\r\n LpTokenFactoryInterface _lpTokenFactory,\r\n FinderInterface _finder,\r\n WETH9 _weth,\r\n address _timer\r\n ) Testable(_timer) {\r\n lpTokenFactory = _lpTokenFactory;\r\n finder = _finder;\r\n weth = _weth;\r\n protocolFeeCaptureAddress = owner();\r\n }\r\n\r\n /*************************************************\r\n * ADMIN FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\r\n * something goes awry.\r\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\r\n */\r\n function setPaused(bool pause) public onlyOwner nonReentrant {\r\n paused = pause;\r\n emit Paused(pause);\r\n }\r\n\r\n /**\r\n * @notice This allows for the deletion of the active proposal in case of emergency.\r\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\r\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\r\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\r\n */\r\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\r\n RootBundle memory _rootBundleProposal = rootBundleProposal;\r\n delete rootBundleProposal;\r\n if (_rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\r\n bondToken.safeTransfer(_rootBundleProposal.proposer, bondAmount);\r\n emit EmergencyRootBundleDeleted(\r\n _rootBundleProposal.poolRebalanceRoot,\r\n _rootBundleProposal.relayerRefundRoot,\r\n _rootBundleProposal.slowRelayRoot,\r\n _rootBundleProposal.proposer\r\n );\r\n }\r\n\r\n /**\r\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\r\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\r\n * contract only allows the owner to call this method directly or indirectly.\r\n * @param chainId Chain with SpokePool to send message to.\r\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\r\n */\r\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n _relaySpokePoolAdminFunction(chainId, functionData);\r\n }\r\n\r\n /**\r\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\r\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\r\n * @param newProtocolFeeCapturePct New protocol fee capture %.\r\n */\r\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\r\n public\r\n override\r\n onlyOwner\r\n nonReentrant\r\n {\r\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\r\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\r\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\r\n protocolFeeCapturePct = newProtocolFeeCapturePct;\r\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\r\n }\r\n\r\n /**\r\n * @notice Sets bond token and amount. Callable only by owner.\r\n * @param newBondToken New bond currency.\r\n * @param newBondAmount New bond amount.\r\n */\r\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\r\n public\r\n override\r\n onlyOwner\r\n noActiveRequests\r\n nonReentrant\r\n {\r\n // Bond should not equal final fee otherwise every proposal will get cancelled in a dispute.\r\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\r\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\r\n require(newBondAmount != 0, \"bond equal to final fee\");\r\n\r\n // Check that this token is on the whitelist.\r\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\r\n );\r\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\r\n\r\n // The bond should be the passed in bondAmount + the final fee.\r\n bondToken = newBondToken;\r\n uint256 _bondAmount = newBondAmount + _getBondTokenFinalFee();\r\n bondAmount = _bondAmount;\r\n emit BondSet(address(newBondToken), _bondAmount);\r\n }\r\n\r\n /**\r\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\r\n * @param newLiveness New liveness period.\r\n */\r\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\r\n require(newLiveness > 10 minutes, \"Liveness too short\");\r\n liveness = newLiveness;\r\n emit LivenessSet(newLiveness);\r\n }\r\n\r\n /**\r\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\r\n * @param newIdentifier New identifier.\r\n */\r\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\r\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\r\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\r\n );\r\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\r\n identifier = newIdentifier;\r\n emit IdentifierSet(newIdentifier);\r\n }\r\n\r\n /**\r\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\r\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\r\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\r\n * @param l2ChainId Chain to set contracts for.\r\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\r\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\r\n */\r\n\r\n function setCrossChainContracts(\r\n uint256 l2ChainId,\r\n address adapter,\r\n address spokePool\r\n ) public override onlyOwner nonReentrant {\r\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\r\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\r\n }\r\n\r\n /**\r\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\r\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\r\n * containing this l1 token + destination chain ID combination.\r\n * @param destinationChainId Destination chain where destination token resides.\r\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\r\n * destination chain ID.\r\n * @param destinationToken Destination chain counterpart of L1 token.\r\n */\r\n function setPoolRebalanceRoute(\r\n uint256 destinationChainId,\r\n address l1Token,\r\n address destinationToken\r\n ) public override onlyOwner nonReentrant {\r\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\r\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\r\n }\r\n\r\n /**\r\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\r\n * SpokePool to another one. Callable only by owner.\r\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\r\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\r\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\r\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\r\n * to the destination chain to refund the relayer.\r\n * @param originChainId Chain where token deposit occurs.\r\n * @param destinationChainId Chain where token depositor wants to receive funds.\r\n * @param originToken Token sent in deposit.\r\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\r\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\r\n */\r\n function setDepositRoute(\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n address originToken,\r\n bool depositsEnabled\r\n ) public override nonReentrant onlyOwner {\r\n _relaySpokePoolAdminFunction(\r\n originChainId,\r\n abi.encodeWithSignature(\r\n \"setEnableRoute(address,uint256,bool)\",\r\n originToken,\r\n destinationChainId,\r\n depositsEnabled\r\n )\r\n );\r\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\r\n }\r\n\r\n /**\r\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\r\n * Callable only by owner.\r\n * @param l1Token Token to provide liquidity for.\r\n */\r\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\r\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\r\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\r\n if (pooledTokens[l1Token].lpToken == address(0)) {\r\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\r\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n pooledTokens[l1Token].isEnabled = true;\r\n\r\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /**\r\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\r\n * @param l1Token Token to disable liquidity provision for.\r\n */\r\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\r\n pooledTokens[l1Token].isEnabled = false;\r\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\r\n }\r\n\r\n /*************************************************\r\n * LIQUIDITY PROVIDER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\r\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\r\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\r\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\r\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\r\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\r\n * increments from the time that they enter the pool to reflect their accrued fees.\r\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\r\n * @param l1Token Token to deposit into this contract.\r\n * @param l1TokenAmount Amount of liquidity to provide.\r\n */\r\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\r\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\r\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\r\n // Else, msg.value must be set to 0.\r\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\r\n\r\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\r\n // first before transferring any tokens to this contract to ensure synchronization.\r\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\r\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\r\n\r\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\r\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\r\n\r\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\r\n * @param l1Token Token to redeem LP share for.\r\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\r\n * via public exchangeRateCurrent method.\r\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\r\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\r\n * if this value is set to False, then the calling contract should have a way to handle WETH.\r\n */\r\n function removeLiquidity(\r\n address l1Token,\r\n uint256 lpTokenAmount,\r\n bool sendEth\r\n ) public override nonReentrant {\r\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\r\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\r\n\r\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\r\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\r\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\r\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\r\n\r\n if (sendEth) {\r\n weth.withdraw(l1TokensToReturn);\r\n Address.sendValue(payable(msg.sender), l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\r\n } else {\r\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\r\n }\r\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\r\n }\r\n\r\n /**\r\n * @notice Returns exchange rate of L1 token to LP token.\r\n * @param l1Token L1 token redeemable by burning LP token.\r\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\r\n */\r\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _exchangeRateCurrent(l1Token);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n * @param l1Token L1 token to query utilization for.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\r\n */\r\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\r\n return _liquidityUtilizationPostRelay(l1Token, 0);\r\n }\r\n\r\n /**\r\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\r\n * relayedAmount of tokens to be withdrawn from the pool.\r\n * @param l1Token L1 token to query utilization for.\r\n * @param relayedAmount The higher this amount, the higher the utilization.\r\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\r\n */\r\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\r\n public\r\n nonReentrant\r\n returns (uint256)\r\n {\r\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\r\n }\r\n\r\n /**\r\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\r\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\r\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\r\n */\r\n function sync(address l1Token) public override nonReentrant {\r\n _sync(l1Token);\r\n }\r\n\r\n /*************************************************\r\n * DATA WORKER FUNCTIONS *\r\n *************************************************/\r\n\r\n /**\r\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\r\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\r\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\r\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\r\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\r\n * called; moreover, this method can't be called again until all leaves are executed.\r\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\r\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\r\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\r\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\r\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\r\n * refund relayers on their chosen refund chainId.\r\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\r\n * fulfill slow relays.\r\n */\r\n function proposeRootBundle(\r\n uint256[] calldata bundleEvaluationBlockNumbers,\r\n uint8 poolRebalanceLeafCount,\r\n bytes32 poolRebalanceRoot,\r\n bytes32 relayerRefundRoot,\r\n bytes32 slowRelayRoot\r\n ) public override nonReentrant noActiveRequests unpaused {\r\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\r\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\r\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\r\n\r\n uint32 challengePeriodEndTimestamp = uint32(getCurrentTime()) + liveness;\r\n\r\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time. Delete the previous bundle.\r\n\r\n rootBundleProposal.challengePeriodEndTimestamp = challengePeriodEndTimestamp;\r\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\r\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\r\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\r\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\r\n rootBundleProposal.proposer = msg.sender;\r\n\r\n // Pull bondAmount of bondToken from the caller.\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n\r\n emit ProposeRootBundle(\r\n challengePeriodEndTimestamp,\r\n poolRebalanceLeafCount,\r\n bundleEvaluationBlockNumbers,\r\n poolRebalanceRoot,\r\n relayerRefundRoot,\r\n slowRelayRoot,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\r\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\r\n * relay roots to the SpokePool on the network specified in the leaf.\r\n * @dev In some cases, will instruct spokePool to send funds back to L1.\r\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\r\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\r\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\r\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\r\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\r\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\r\n * @param leafId Index of this executed leaf within the poolRebalance tree.\r\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\r\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\r\n */\r\n\r\n function executeRootBundle(\r\n uint256 chainId,\r\n uint256 groupIndex,\r\n uint256[] memory bundleLpFees,\r\n int256[] memory netSendAmounts,\r\n int256[] memory runningBalances,\r\n uint8 leafId,\r\n address[] memory l1Tokens,\r\n bytes32[] calldata proof\r\n ) public nonReentrant unpaused {\r\n require(getCurrentTime() > rootBundleProposal.challengePeriodEndTimestamp, \"Not passed liveness\");\r\n\r\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\r\n\r\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\r\n require(\r\n MerkleLib.verifyPoolRebalance(\r\n rootBundleProposal.poolRebalanceRoot,\r\n PoolRebalanceLeaf({\r\n chainId: chainId,\r\n groupIndex: groupIndex,\r\n bundleLpFees: bundleLpFees,\r\n netSendAmounts: netSendAmounts,\r\n runningBalances: runningBalances,\r\n leafId: leafId,\r\n l1Tokens: l1Tokens\r\n }),\r\n proof\r\n ),\r\n \"Bad Proof\"\r\n );\r\n // Grouping code that uses adapter and spokepool to avoid stack too deep warning.\r\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\r\n // is set improperly.\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Set the leafId in the claimed bitmap.\r\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\r\n\r\n // Decrement the unclaimedPoolRebalanceLeafCount.\r\n --rootBundleProposal.unclaimedPoolRebalanceLeafCount;\r\n\r\n // Relay each L1 token to destination chain.\r\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\r\n // then this internal method will revert. In this case the admin will have to associate a destination token\r\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\r\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\r\n // determine if the relayers used the correct destination token for a given origin token.\r\n _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n adapter,\r\n spokePool,\r\n chainId,\r\n l1Tokens,\r\n netSendAmounts,\r\n bundleLpFees\r\n );\r\n\r\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\r\n if (groupIndex == 0) {\r\n // Relay root bundles to spoke pool on destination chain by\r\n // performing delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n abi.encodeWithSignature(\r\n \"relayRootBundle(bytes32,bytes32)\",\r\n rootBundleProposal.relayerRefundRoot,\r\n rootBundleProposal.slowRelayRoot\r\n ) // message\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\r\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\r\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\r\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\r\n\r\n emit RootBundleExecuted(\r\n groupIndex,\r\n leafId,\r\n chainId,\r\n l1Tokens,\r\n bundleLpFees,\r\n netSendAmounts,\r\n runningBalances,\r\n msg.sender\r\n );\r\n }\r\n\r\n /**\r\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\r\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\r\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\r\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\r\n */\r\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\r\n uint32 currentTime = uint32(getCurrentTime());\r\n require(currentTime <= rootBundleProposal.challengePeriodEndTimestamp, \"Request passed liveness\");\r\n\r\n // Request price from OO and dispute it.\r\n uint256 finalFee = _getBondTokenFinalFee();\r\n\r\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\r\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\r\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\r\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\r\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\r\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\r\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\r\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\r\n // data in this ancillary data that is already included in the ProposeRootBundle event.\r\n\r\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\r\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\r\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\r\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\r\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\r\n if (finalFee >= bondAmount) {\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\r\n\r\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n try\r\n optimisticOracle.requestAndProposePriceFor(\r\n identifier,\r\n currentTime,\r\n \"\",\r\n bondToken,\r\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\r\n // proposal has passed the challenge period.\r\n 0,\r\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\r\n bondAmount - finalFee,\r\n // Set the Optimistic oracle liveness for the price request.\r\n liveness,\r\n rootBundleProposal.proposer,\r\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\r\n int256(1e18)\r\n )\r\n returns (uint256) {\r\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\r\n // to transfer than intended.\r\n bondToken.safeApprove(address(optimisticOracle), 0);\r\n } catch {\r\n // Cancel the bundle since the proposal failed.\r\n _cancelBundle();\r\n return;\r\n }\r\n\r\n // Dispute the request that we just sent.\r\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\r\n proposer: rootBundleProposal.proposer,\r\n disputer: address(0),\r\n currency: bondToken,\r\n settled: false,\r\n proposedPrice: int256(1e18),\r\n resolvedPrice: 0,\r\n expirationTime: currentTime + liveness,\r\n reward: 0,\r\n finalFee: finalFee,\r\n bond: bondAmount - finalFee,\r\n customLiveness: liveness\r\n });\r\n\r\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\r\n delete rootBundleProposal;\r\n\r\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\r\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\r\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\r\n\r\n emit RootBundleDisputed(msg.sender, currentTime);\r\n }\r\n\r\n /**\r\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\r\n * @param l1Token Token whose protocol fees the caller wants to disburse.\r\n */\r\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\r\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\r\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\r\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\r\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\r\n }\r\n\r\n /**\r\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\r\n * @dev Admin must be considerate to the compatibility of originToken and destinationToken within the protocol. Some\r\n * token implementations will not function correctly within the Across v2 system. For example ERC20s that charge\r\n * fees will break internal accounting, ERC777 can cause some functions to revert and upgradable tokens can pose\r\n * risks if the implementation is shifted between whitelisting and usage.\r\n * @dev If the pool rebalance route is not whitelisted then this will return address(0).\r\n * @param destinationChainId Where destination token is deployed.\r\n * @param l1Token Ethereum version token.\r\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\r\n * the l1Token to the destination chain.\r\n */\r\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\r\n external\r\n view\r\n override\r\n returns (address destinationToken)\r\n {\r\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\r\n }\r\n\r\n /**\r\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\r\n * Arbitrum calls, but may also be needed for others.\r\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\r\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\r\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\r\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\r\n */\r\n function loadEthForL2Calls() public payable override {\r\n /* solhint-disable-line no-empty-blocks */\r\n }\r\n\r\n /*************************************************\r\n * INTERNAL FUNCTIONS *\r\n *************************************************/\r\n\r\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\r\n // with no loss of funds, thereby enabling a new bundle to be added.\r\n function _cancelBundle() internal {\r\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\r\n delete rootBundleProposal;\r\n emit RootBundleCanceled(msg.sender, getCurrentTime());\r\n }\r\n\r\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\r\n return\r\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\r\n }\r\n\r\n function _getBondTokenFinalFee() internal view returns (uint256) {\r\n return\r\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\r\n .computeFinalFee(address(bondToken))\r\n .rawValue;\r\n }\r\n\r\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\r\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\r\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\r\n address adapter,\r\n address spokePool,\r\n uint256 chainId,\r\n address[] memory l1Tokens,\r\n int256[] memory netSendAmounts,\r\n uint256[] memory bundleLpFees\r\n ) internal {\r\n uint256 length = l1Tokens.length;\r\n for (uint256 i = 0; i < length; ) {\r\n address l1Token = l1Tokens[i];\r\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\r\n // could send tokens to the 0x0 address on the L2.\r\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\r\n require(l2Token != address(0), \"Route not whitelisted\");\r\n\r\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\r\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\r\n if (netSendAmounts[i] > 0) {\r\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\r\n // complexity in exchange for lower gas costs.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayTokens(address,address,uint256,address)\",\r\n l1Token, // l1Token.\r\n l2Token, // l2Token.\r\n uint256(netSendAmounts[i]), // amount.\r\n spokePool // to. This should be the spokePool.\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n\r\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\r\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\r\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\r\n }\r\n\r\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\r\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\r\n\r\n // L1 tokens length won't be > types(uint256).length, so use unchecked block to save gas. Based on the\r\n // stress test results in /test/gas-analytics/HubPool.RootExecution.ts, the UMIP should limit the L1 token\r\n // count in valid proposals to be ~100 so any PoolRebalanceLeaves with > 100 l1Tokens should not make it\r\n // to this stage.\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n }\r\n\r\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\r\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\r\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\r\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\r\n\r\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\r\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\r\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\r\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\r\n // gradually increase over time as undistributedLpFees goes to zero.\r\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\r\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\r\n // int will always be positive so there is no risk in underflow in type casting in the return line.\r\n int256 numerator = int256(pooledToken.liquidReserves) +\r\n pooledToken.utilizedReserves -\r\n int256(pooledToken.undistributedLpFees);\r\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\r\n }\r\n\r\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\r\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\r\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\r\n pooledToken.undistributedLpFees -= accumulatedFees;\r\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\r\n }\r\n\r\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\r\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\r\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\r\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\r\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\r\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\r\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\r\n }\r\n\r\n function _sync(address l1Token) internal {\r\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\r\n // action from L2 -> L1 has concluded and the local accounting can be updated.\r\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\r\n // active request.\r\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\r\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\r\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\r\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\r\n // dropped onto the contract, exceeding the liquidReserves.\r\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\r\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\r\n }\r\n }\r\n\r\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\r\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\r\n\r\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\r\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\r\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\r\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\r\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\r\n PooledToken memory pooledL1Token = pooledTokens[l1Token];\r\n uint256 flooredUtilizedReserves = pooledL1Token.utilizedReserves > 0\r\n ? uint256(pooledL1Token.utilizedReserves) // If positive: take the uint256 cast utilizedReserves.\r\n : 0; // Else, if negative, then the is already captured in liquidReserves and should be ignored.\r\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\r\n uint256 denominator = pooledL1Token.liquidReserves + flooredUtilizedReserves;\r\n\r\n // If the denominator equals zero, return 1e18 (max utilization).\r\n if (denominator == 0) return 1e18;\r\n\r\n // In all other cases, return the utilization ratio.\r\n return (numerator * 1e18) / denominator;\r\n }\r\n\r\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\r\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\r\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\r\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\r\n\r\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\r\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\r\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\r\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\r\n if (lpFeesCaptured > 0) {\r\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\r\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\r\n }\r\n\r\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\r\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\r\n }\r\n\r\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\r\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\r\n\r\n // Perform delegatecall to use the adapter's code with this contract's context.\r\n\r\n // We are ok with this low-level call since the adapter address is set by the admin and we've\r\n // already checked that its not the zero address.\r\n // solhint-disable-next-line avoid-low-level-calls\r\n (bool success, ) = adapter.delegatecall(\r\n abi.encodeWithSignature(\r\n \"relayMessage(address,bytes)\",\r\n spokePool, // target. This should be the spokePool on the L2.\r\n functionData\r\n )\r\n );\r\n require(success, \"delegatecall failed\");\r\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\r\n }\r\n\r\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\r\n return keccak256(abi.encode(l1Token, destinationChainId));\r\n }\r\n\r\n function _getInitializedCrossChainContracts(uint256 chainId)\r\n internal\r\n view\r\n returns (address adapter, address spokePool)\r\n {\r\n adapter = crossChainContracts[chainId].adapter;\r\n spokePool = crossChainContracts[chainId].spokePool;\r\n require(spokePool != address(0), \"SpokePool not initialized\");\r\n require(adapter.isContract(), \"Adapter not initialized\");\r\n }\r\n\r\n function _activeRequest() internal view returns (bool) {\r\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\r\n }\r\n\r\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\r\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\r\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\r\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\r\n function _depositEthToWeth() internal {\r\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\r\n }\r\n\r\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\r\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\r\n fallback() external payable {\r\n _depositEthToWeth();\r\n }\r\n\r\n receive() external payable {\r\n _depositEthToWeth();\r\n }\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -59,19 +59,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -80,7 +80,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/optimism-kovan/Optimism_SpokePool.json b/deployments/optimism-kovan/Optimism_SpokePool.json index 6aca2574..2f62559d 100644 --- a/deployments/optimism-kovan/Optimism_SpokePool.json +++ b/deployments/optimism-kovan/Optimism_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\n\\n/**\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\n // unused by bridge but included for future compatibility.\\n uint32 public l1Gas = 5_000_000;\\n\\n // ETH is an ERC20 on OVM.\\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\\n\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\n mapping(address => address) public tokenBridges;\\n\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\n event SetL1Gas(uint32 indexed newL1Gas);\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\n\\n /**\\n * @notice Construct the OVM SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address timerAddress\\n )\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\\n {}\\n\\n /*******************************************\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\n *******************************************/\\n\\n /**\\n * @notice Change L1 gas limit. Callable only by admin.\\n * @param newl1Gas New L1 gas limit to set.\\n */\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\n l1Gas = newl1Gas;\\n emit SetL1Gas(newl1Gas);\\n }\\n\\n /**\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\n * @param tokenBridge Address of token bridge\\n */\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\n tokenBridges[l2Token] = tokenBridge;\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 totalRelayAmount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n totalRelayAmount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\n // on the OVM.\\n function _depositEthToWeth() internal {\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\n }\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\n }\\n IL2ERC20Bridge(\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\n ).withdrawTo(\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\n }\\n\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\n}\\n\",\"keccak256\":\"0xe8a9ceea10e37bc4a1aef16a3337811d176cf92520b103272d86e472f450d2a1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\n\\n/**\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\\n */\\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\n // unused by bridge but included for future compatibility.\\n uint32 public l1Gas = 5_000_000;\\n\\n // ETH is an ERC20 on OVM.\\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\\n\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\n mapping(address => address) public tokenBridges;\\n\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\n event SetL1Gas(uint32 indexed newL1Gas);\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\n\\n /**\\n * @notice Construct the OVM SpokePool.\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _crossDomainAdmin,\\n address _hubPool,\\n address timerAddress\\n )\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\\n {}\\n\\n /*******************************************\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\n *******************************************/\\n\\n /**\\n * @notice Change L1 gas limit. Callable only by admin.\\n * @param newl1Gas New L1 gas limit to set.\\n */\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\n l1Gas = newl1Gas;\\n emit SetL1Gas(newl1Gas);\\n }\\n\\n /**\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\n * @param tokenBridge Address of token bridge\\n */\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\n tokenBridges[l2Token] = tokenBridge;\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\n }\\n\\n /**************************************\\n * DATA WORKER FUNCTIONS *\\n **************************************/\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 totalRelayAmount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeSlowRelayLeaf(\\n depositor,\\n recipient,\\n destinationToken,\\n totalRelayAmount,\\n originChainId,\\n chainId(),\\n realizedLpFeePct,\\n relayerFeePct,\\n depositId,\\n rootBundleId,\\n proof\\n );\\n }\\n\\n /**\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\n * ETH over the canonical token bridge instead of WETH.\\n * @inheritdoc SpokePool\\n */\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) public override(SpokePool) nonReentrant {\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\n\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\n }\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\n // on the OVM.\\n function _depositEthToWeth() internal {\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\n }\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\n }\\n IL2ERC20Bridge(\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\n ).withdrawTo(\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\n relayerRefundLeaf.amountToReturn, // _amount.\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\n );\\n\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\n }\\n\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\n}\\n\",\"keccak256\":\"0xe8a9ceea10e37bc4a1aef16a3337811d176cf92520b103272d86e472f450d2a1\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b4017905573deaddeaddeaddeaddeaddeaddeaddeaddead000060a0523480156200005357600080fd5b5060405162004c8938038062004c89833981016040819052620000769162000269565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273420000000000000000000000000000000000000683620000e08462000104565b620000eb83620001aa565b506001600160a01b031660805250620002b39350505050565b6001600160a01b038116620001605760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002025760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000157565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200026457600080fd5b919050565b6000806000606084860312156200027f57600080fd5b6200028a846200024c565b92506200029a602085016200024c565b9150620002aa604085016200024c565b90509250925092565b60805160a05161496a6200031f600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d2f5cc3730c17bef6c253d4fdf81eecdd0f59a76612528a3f30f63eb1b2c7eca64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d2f5cc3730c17bef6c253d4fdf81eecdd0f59a76612528a3f30f63eb1b2c7eca64736f6c634300080d0033", "devdoc": { diff --git a/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index a0cc1d52..2a6425e5 100644 --- a/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/optimism-kovan/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/optimism/Optimism_SpokePool.json b/deployments/optimism/Optimism_SpokePool.json index 109a09c9..7a911374 100644 --- a/deployments/optimism/Optimism_SpokePool.json +++ b/deployments/optimism/Optimism_SpokePool.json @@ -1213,7 +1213,7 @@ ], "numDeployments": 1, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Optimism SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Optimism Spoke pool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Optimism Spoke pool.\\r\\n */\\r\\ncontract Optimism_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Optimism SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n Lib_PredeployAddresses.OVM_ETH,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x73c37ddf9651c2b34bfc877502b44bc0f271498206dfe4446e7b653567920a53\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"numberOfTokensBridged\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1Gas\",\"type\":\"uint256\"}],\"name\":\"OptimismTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"newL1Gas\",\"type\":\"uint32\"}],\"name\":\"SetL1Gas\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"SetL2TokenBridge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"totalRelayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Gas\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Eth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newl1Gas\",\"type\":\"uint32\"}],\"name\":\"setL1GasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenBridge\",\"type\":\"address\"}],\"name\":\"setTokenBridge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenBridges\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setL1GasLimit(uint32)\":{\"params\":{\"newl1Gas\":\"New L1 gas limit to set.\"}},\"setTokenBridge(address,address)\":{\"details\":\"If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\",\"params\":{\"tokenBridge\":\"Address of token bridge\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the OVM Optimism SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives ETH over the canonical token bridge instead of WETH.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setL1GasLimit(uint32)\":{\"notice\":\"Change L1 gas limit. Callable only by admin.\"},\"setTokenBridge(address,address)\":{\"notice\":\"Set bridge contract for L2 token used to withdraw back to L1.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Optimism Spoke pool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Optimism_SpokePool.sol\":\"Optimism_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title IL2ERC20Bridge\\n */\\ninterface IL2ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event WithdrawalInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event DepositFailed(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L1 bridge contract.\\n * @return Address of the corresponding L1 bridge contract.\\n */\\n function l1TokenBridge() external returns (address);\\n\\n /**\\n * @dev initiate a withdraw of some tokens to the caller's account on L1\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdraw(\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev initiate a withdraw of some token to a recipient's account on L1.\\n * @param _l2Token Address of L2 token where withdrawal is initiated.\\n * @param _to L1 adress to credit the withdrawal to.\\n * @param _amount Amount of the token to withdraw.\\n * param _l1Gas Unused, but included for potential forward compatibility considerations.\\n * @param _data Optional data to forward to L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function withdrawTo(\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l1Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this\\n * L2 token. This call will fail if it did not originate from a corresponding deposit in\\n * L1StandardTokenBridge.\\n * @param _l1Token Address for the l1 token this is called with\\n * @param _l2Token Address for the l2 token this is called with\\n * @param _from Account to pull the deposit from on L2.\\n * @param _to Address to receive the withdrawal at\\n * @param _amount Amount of the token to withdraw\\n * @param _data Data provider by the sender on L1. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeDeposit(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x4674c3c8733ca0db16c2b81d58227560df36a07ded3b637a0793564d90ac0475\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"./ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications\\n *\\n * Compiler used: defined by inheriting contract\\n */\\ncontract CrossDomainEnabled {\\n /*************\\n * Variables *\\n *************/\\n\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public messenger;\\n\\n /***************\\n * Constructor *\\n ***************/\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**********************\\n * Function Modifiers *\\n **********************/\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(\\n msg.sender == address(getCrossDomainMessenger()),\\n \\\"OVM_XCHAIN: messenger contract unauthenticated\\\"\\n );\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**********************\\n * Internal Functions *\\n **********************/\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**q\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * `onlyFromCrossDomainAccount()`)\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0x9c3cc8b7047c68a403529b15769a21c2e2668ea71db7bef51f123288009811ea\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\n/**\\n * @title Lib_PredeployAddresses\\n */\\nlibrary Lib_PredeployAddresses {\\n address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;\\n address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;\\n address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;\\n address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);\\n address internal constant L2_CROSS_DOMAIN_MESSENGER =\\n 0x4200000000000000000000000000000000000007;\\n address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;\\n address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;\\n address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;\\n address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;\\n address internal constant L2_STANDARD_TOKEN_FACTORY =\\n 0x4200000000000000000000000000000000000012;\\n address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;\\n}\\n\",\"keccak256\":\"0x2bc28307af93e9716151a41a81694b56cbe513ef5eb335fb1d81f35e5db8edfa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/Optimism_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\n\\r\\nimport \\\"./Ovm_SpokePool.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice Optimism Spoke pool.\\r\\n */\\r\\ncontract Optimism_SpokePool is Ovm_SpokePool {\\r\\n /**\\r\\n * @notice Construct the OVM Optimism SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address timerAddress\\r\\n )\\r\\n Ovm_SpokePool(\\r\\n _crossDomainAdmin,\\r\\n _hubPool,\\r\\n Lib_PredeployAddresses.OVM_ETH,\\r\\n 0x4200000000000000000000000000000000000006,\\r\\n timerAddress\\r\\n )\\r\\n {}\\r\\n}\\r\\n\",\"keccak256\":\"0x73c37ddf9651c2b34bfc877502b44bc0f271498206dfe4446e7b653567920a53\",\"license\":\"GPL-3.0-only\"},\"contracts/Ovm_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\\\";\\r\\nimport \\\"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\\\";\\r\\n\\r\\n/**\\r\\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\\r\\n */\\r\\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\\r\\n // \\\"l1Gas\\\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\\r\\n // unused by bridge but included for future compatibility.\\r\\n uint32 public l1Gas = 5_000_000;\\r\\n\\r\\n // ETH is an ERC20 on OVM.\\r\\n address public immutable l2Eth;\\r\\n\\r\\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\\r\\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\\r\\n mapping(address => address) public tokenBridges;\\r\\n\\r\\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\\r\\n event SetL1Gas(uint32 indexed newL1Gas);\\r\\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\\r\\n\\r\\n /**\\r\\n * @notice Construct the OVM SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _l2Eth,\\r\\n address _wrappedNativeToken,\\r\\n address timerAddress\\r\\n )\\r\\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\\r\\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\\r\\n {\\r\\n l2Eth = _l2Eth;\\r\\n }\\r\\n\\r\\n /*******************************************\\r\\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\\r\\n *******************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change L1 gas limit. Callable only by admin.\\r\\n * @param newl1Gas New L1 gas limit to set.\\r\\n */\\r\\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\\r\\n l1Gas = newl1Gas;\\r\\n emit SetL1Gas(newl1Gas);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\\r\\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\\r\\n * @param tokenBridge Address of token bridge\\r\\n */\\r\\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\\r\\n tokenBridges[l2Token] = tokenBridge;\\r\\n emit SetL2TokenBridge(l2Token, tokenBridge);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 totalRelayAmount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n totalRelayAmount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\\r\\n * ETH over the canonical token bridge instead of WETH.\\r\\n * @inheritdoc SpokePool\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override(SpokePool) nonReentrant {\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\\r\\n\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\\r\\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\\r\\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\\r\\n // on the OVM.\\r\\n function _depositEthToWeth() internal {\\r\\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\\r\\n }\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\\r\\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\\r\\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\\r\\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\\r\\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\\r\\n }\\r\\n IL2ERC20Bridge(\\r\\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\\r\\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\\r\\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\\r\\n ).withdrawTo(\\r\\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\\r\\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\\r\\n relayerRefundLeaf.amountToReturn, // _amount.\\r\\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\\r\\n \\\"\\\" // _data. We don't need to send any data for the bridging action.\\r\\n );\\r\\n\\r\\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\\r\\n }\\r\\n\\r\\n // Apply OVM-specific transformation to cross domain admin address on L1.\\r\\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\\r\\n}\\r\\n\",\"keccak256\":\"0xa93d856cc2352ef386bd573e3091e6336fd65576c404020fd9db3a4cd5f32cb4\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405260038054604b60a31b63ffffffff60a01b199091161790556007805463ffffffff1916624c4b401790553480156200003b57600080fd5b5060405162004c9738038062004c978339810160408190526200005e9162000277565b600080546001600160a01b031916734200000000000000000000000000000000000007179055600180546001600160a81b0319166001600160a01b03831617600160a01b179055828273deaddeaddeaddeaddeaddeaddeaddeaddead00007342000000000000000000000000000000000000068484848383620000e18462000112565b620000ec83620001b8565b506001600160a01b039081166080529490941660a05250620002c1975050505050505050565b6001600160a01b0381166200016e5760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620002105760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c2061646472657373000000000000000000000000604482015260640162000165565b600380546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b80516001600160a01b03811681146200027257600080fd5b919050565b6000806000606084860312156200028d57600080fd5b62000298846200025a565b9250620002a8602085016200025a565b9150620002b8604085016200025a565b90509250925092565b60805160a05161496a6200032d600039600081816106250152612dd201526000818161021c0152818161080001528181610ee801528181610fb10152818161168601528181611e330152818161269b01528181612cd9015281816131420152613198015261496a6000f3fe6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212209da4bba922e72e8a4d613325bde7422470ee1aea7d82220d65f7da5c44f56f0c64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c8063766e070311610102578063de7eba7811610095578063ee2a53f811610064578063ee2a53f814610647578063f06850f61461067c578063fbbba9ac146106a9578063ffc351a3146106c957600080fd5b8063de7eba78146105a6578063e1904402146105c6578063e282d5b9146105f3578063e32292111461061357600080fd5b8063a1244c67116100d1578063a1244c67146104ea578063ac9650d814610523578063b27a430014610543578063be3576ee1461058657600080fd5b8063766e07031461047a57806389a153cc146104975780638a7860ce146104b75780639a8a0592146104d757600080fd5b80632752042e1161017a578063493a4f8411610149578063493a4f84146103985780635249fef1146103b85780635285e0581461040357806357f6dcb81461043057600080fd5b80632752042e1461031557806329cb924d146103355780633cb747bf14610358578063492289781461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b80630eaac9f0146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a20565b6106e9565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c02565b6107c9565b34801561029457600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613cfe565b6108b1565b3480156102e157600080fd5b506102086102f0366004613d1b565b61093b565b34801561030157600080fd5b50610208610310366004613d42565b6109e4565b34801561032157600080fd5b50610208610330366004613a20565b610af6565b34801561034157600080fd5b5061034a610bf7565b60405190815260200161025f565b34801561036457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b610208610393366004613d9c565b610cb3565b3480156103a457600080fd5b506102086103b3366004613e06565b61112a565b3480156103c457600080fd5b506103f36103d3366004613e28565b600560209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561040f57600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043c57600080fd5b506003546104659074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b34801561048657600080fd5b506007546104659063ffffffff1681565b3480156104a357600080fd5b506102086104b2366004613e54565b611245565b3480156104c357600080fd5b506102086104d2366004613d1b565b6113a1565b3480156104e357600080fd5b504661034a565b3480156104f657600080fd5b50600354610465907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610536610531366004613ef8565b611475565b60405161025f9190613fe3565b34801561054f57600080fd5b5061023e61055e366004613cfe565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561059257600080fd5b506102086105a1366004614063565b61164f565b3480156105b257600080fd5b506102086105c1366004613cfe565b611736565b3480156105d257600080fd5b5060035461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105ff57600080fd5b5061020861060e3660046141c7565b61177c565b34801561061f57600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065357600080fd5b50610667610662366004613d1b565b6118da565b6040805192835260208301919091520161025f565b34801561068857600080fd5b5061034a610697366004613d1b565b60066020526000908152604090205481565b3480156106b557600080fd5b506102086106c4366004614238565b611908565b3480156106d557600080fd5b506102086106e4366004614271565b611a01565b6106f1611b6c565b6106f9611da5565b610726600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83169081179091556040517fe486a5c4bd7b36eabbfe274c99b39130277417be8d2209b4dae04c4fba64ee3a90600090a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107d1611da5565b6107fe600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826080015173ffffffffffffffffffffffffffffffffffffffff160361085d5761085d611e2b565b610868838383611e99565b6108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6108b9611b6c565b6108c1611da5565b6108ee600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612245565b6107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015473ffffffffffffffffffffffffffffffffffffffff1661095d57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156109c957600080fd5b505af11580156109dd573d6000803e3d6000fd5b5050505050565b6109ec611b6c565b6109f4611da5565b610a21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260056020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36108ac600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610afe611b6c565b610b06611da5565b610b33600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600380547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff1615610cae57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca9919061434f565b905090565b504290565b610cbb611da5565b610ce8600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260056020908152604080832086845290915290205460ff16610d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610e02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b600354610e2d9074010000000000000000000000000000000000000000900463ffffffff1682614397565b63ffffffff16610e3b610bf7565b10158015610e805750600354610e6f9074010000000000000000000000000000000000000000900463ffffffff16826143bc565b63ffffffff16610e7d610bf7565b11155b610ee6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610f415750600034115b1561103557833414610faf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d7e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505050611057565b61105773ffffffffffffffffffffffffffffffffffffffff8616333087612331565b61108e8446600354869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d3361240d565b600380546018906110c0907801000000000000000000000000000000000000000000000000900463ffffffff166143e4565b91906101000a81548163ffffffff021916908363ffffffff160217905550611122600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b611132611b6c565b61113a611da5565b611167600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600480546001810182556000918252600381027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c81018590557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a45050611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b61124d611da5565b61127a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112ef4690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff168152509050600061132b8261249e565b9050600061133d82848b8860006124ce565b905061134e82828a8887600061277b565b505050611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b6113a9611b6c565b6113b1611da5565b6113de600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600481815481106113f1576113f1614407565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107c6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b606034156114df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d7e565b8167ffffffffffffffff8111156114f8576114f8613a3b565b60405190808252806020026020018201604052801561152b57816020015b60608152602001906001900390816115165790505b50905060005b82811015611648576000803086868581811061154f5761154f614407565b90506020028101906115619190614436565b60405161156f92919061449b565b600060405180830381855af49150503d80600081146115aa576040519150601f19603f3d011682016040523d82523d6000602084013e6115af565b606091505b509150915081611615576044815110156115c857600080fd5b600481019050808060200190518101906115e291906144ab565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b8084848151811061162857611628614407565b6020026020010181905250505080806116409061452c565b915050611531565b5092915050565b611657611da5565b611684600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036116df576116df611e2b565b6116f28a8a8a8a8a468b8b8b8b8b6128bd565b611395600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61173e611b6c565b611746611da5565b611773600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6108f781612a3c565b611784611da5565b6117b1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061182c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d7e565b6118398446858585612b28565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611888929190614564565b60405180910390a36118d4600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b600481815481106118ea57600080fd5b60009182526020909120600390910201805460019091015490915082565b611910611b6c565b611918611da5565b611945600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526008602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517ff3dc137d2246f9b8abd0bb821e185ba01122c9b3ea3745ffca6208037674d6709190a3611241600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a09611da5565b611a36600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a438c87858585612b28565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611ab84690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611af48261249e565b90506000611b0682848d8960006124ce565b9050611b1782828c8987600061277b565b505050611b5e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16611ba460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e746963617465640000000000000000000000000000000000006064820152608401610d7e565b8073ffffffffffffffffffffffffffffffffffffffff16611c9460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d029190614587565b73ffffffffffffffffffffffffffffffffffffffff16146107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610d7e565b60015474010000000000000000000000000000000000000000900460ff16611e29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d7e565b565b4715611e29577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109c957600080fd5b46826020015114611f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d7e565b8160400151518260a001515114611f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d7e565b600060048463ffffffff1681548110611f9457611f94614407565b90600052602060002090600302019050611fb381600101548484612bc5565b612019576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d7e565b61203081600201846060015163ffffffff16612c02565b15612097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d7e565b6120ae81600201846060015163ffffffff16612c43565b60408301515160005b8181101561213f576000856040015182815181106120d7576120d7614407565b602002602001015190506000811115612136576121368660a00151838151811061210357612103614407565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b506001016120b7565b508351156121d85761215084612cd7565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516121cf92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612236959493929190614625565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81166122c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d7e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118d49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612f9c565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6000816040516020016124b19190614683565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff1610801561250657506706f05b59d3b200008560c0015167ffffffffffffffff16105b61256c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d7e565b6060850151600087815260066020526040902054106125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d7e565b836000036125f757506000612772565b61261084848760c0015161260b919061472a565b6130a8565b60008781526006602052604081205460608801519293508692612633919061474d565b90508281101561265c5780925061265983868960c00151612654919061472a565b6130e2565b91505b6000888152600660205260408120805485929061267a908490614764565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691160361270257836126ef5760408701516126ef9073ffffffffffffffffffffffffffffffffffffffff16333085612331565b6126fd87602001518361310b565b61276f565b8361273c576126fd338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612331909392919063ffffffff16565b61276f876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612c819092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600660008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f6040516128ad9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061299260048463ffffffff168154811061297957612979614407565b906000526020600020906003020160000154828461324c565b6129f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d7e565b6000612a038261249e565b90506000612a1a82848560600151600060016124ce565b9050612a2c828260008087600161277b565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d7e565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612baf82613264565b9050612bbc87828561329f565b50505050505050565b6000612bf8828585604051602001612bdd919061477c565b6040516020818303038152906040528051906020012061333d565b90505b9392505050565b600080612c1161010084614846565b90506000612c216101008561485a565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612c5161010083614846565b90506000612c616101008461485a565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108ac9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161238b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff1603612df957608081015181516040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691632e1a7d4d91612d8a9160040190815260200190565b600060405180830381600087803b158015612da457600080fd5b505af1158015612db8573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166080830152505b608081015173ffffffffffffffffffffffffffffffffffffffff9081166000908152600860205260409020541615612e5d57608081015173ffffffffffffffffffffffffffffffffffffffff90811660009081526008602052604090205416612e73565b7342000000000000000000000000000000000000105b608082015160035483516007546040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152604483019190915263ffffffff16606482015260a06084820152600060a482015291169063a3a795489060c401600060405180830381600087803b158015612f1257600080fd5b505af1158015612f26573d6000803e3d6000fd5b50505050608081015160035482516007546040805173ffffffffffffffffffffffffffffffffffffffff9485168152602081019390935263ffffffff909116908201529116907f46b77e3c29797b94890fd3438da74f697480742358a3e26b9d13a227f1ac0ac99060600160405180910390a250565b6000612ffe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133539092919063ffffffff16565b8051909150156108ac578080602001905181019061301c919061486e565b6108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d7e565b60006130bc82670de0b6b3a764000061488b565b67ffffffffffffffff166130d884670de0b6b3a76400006148ac565b612bfb9190614846565b6000670de0b6b3a76400006130f7838261488b565b6130d89067ffffffffffffffff16856148ac565b73ffffffffffffffffffffffffffffffffffffffff82163b156131695761124173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612c81565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156108ac573d6000803e3d6000fd5b6000612bf8828585604051602001612bdd9190614683565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c016124b1565b6132a98282613362565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146108ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d7e565b60008261334a8584613386565b14949350505050565b6060612bf884846000856133f2565b60008060006133718585613588565b9150915061337e816135f6565b509392505050565b600081815b845181101561337e5760008582815181106133a8576133a8614407565b602002602001015190508083116133ce57600083815260208290526040902092506133df565b600081815260208490526040902092505b50806133ea8161452c565b91505061338b565b606082471015613484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d7e565b73ffffffffffffffffffffffffffffffffffffffff85163b613502576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d7e565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161352b91906148e9565b60006040518083038185875af1925050503d8060008114613568576040519150601f19603f3d011682016040523d82523d6000602084013e61356d565b606091505b509150915061357d82828661384a565b979650505050505050565b60008082516041036135be5760208301516040840151606085015160001a6135b28782858561389d565b945094505050506135ef565b82516040036135e757602083015160408401516135dc8683836139b5565b9350935050506135ef565b506000905060025b9250929050565b600081600481111561360a5761360a614905565b036136125750565b600181600481111561362657613626614905565b0361368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d7e565b60028160048111156136a1576136a1614905565b03613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d7e565b600381600481111561371c5761371c614905565b036137a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60048160048111156137bd576137bd614905565b036107c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d7e565b60608315613859575081612bfb565b8251156138695782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7e9190614519565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156138d457506000905060036139ac565b8460ff16601b141580156138ec57508460ff16601c14155b156138fd57506000905060046139ac565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613951573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139a5576000600192509250506139ac565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316816139eb60ff86901c601b614764565b90506139f98782888561389d565b935093505050935093915050565b803563ffffffff81168114613a1b57600080fd5b919050565b600060208284031215613a3257600080fd5b612bfb82613a07565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613a8d57613a8d613a3b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a3b565b604052919050565b600067ffffffffffffffff821115613afc57613afc613a3b565b5060051b60200190565b600082601f830112613b1757600080fd5b81356020613b2c613b2783613ae2565b613a93565b82815260059290921b84018101918181019086841115613b4b57600080fd5b8286015b84811015613b665780358352918301918301613b4f565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107c657600080fd5b8035613a1b81613b71565b600082601f830112613baf57600080fd5b81356020613bbf613b2783613ae2565b82815260059290921b84018101918181019086841115613bde57600080fd5b8286015b84811015613b66578035613bf581613b71565b8352918301918301613be2565b600080600060608486031215613c1757600080fd5b613c2084613a07565b9250602084013567ffffffffffffffff80821115613c3d57600080fd5b9085019060c08288031215613c5157600080fd5b613c59613a6a565b8235815260208301356020820152604083013582811115613c7957600080fd5b613c8589828601613b06565b604083015250613c9760608401613a07565b6060820152613ca860808401613b93565b608082015260a083013582811115613cbf57600080fd5b613ccb89828601613b9e565b60a08301525093506040860135915080821115613ce757600080fd5b50613cf486828701613b06565b9150509250925092565b600060208284031215613d1057600080fd5b8135612bfb81613b71565b600060208284031215613d2d57600080fd5b5035919050565b80151581146107c657600080fd5b600080600060608486031215613d5757600080fd5b8335613d6281613b71565b9250602084013591506040840135613d7981613d34565b809150509250925092565b803567ffffffffffffffff81168114613a1b57600080fd5b60008060008060008060c08789031215613db557600080fd5b8635613dc081613b71565b95506020870135613dd081613b71565b94506040870135935060608701359250613dec60808801613d84565b9150613dfa60a08801613a07565b90509295509295509295565b60008060408385031215613e1957600080fd5b50508035926020909101359150565b60008060408385031215613e3b57600080fd5b8235613e4681613b71565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613e7457600080fd5b8a35613e7f81613b71565b995060208b0135613e8f81613b71565b985060408b0135613e9f81613b71565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613ec960e08c01613d84565b9250613ed86101008c01613d84565b9150613ee76101208c01613a07565b90509295989b9194979a5092959850565b60008060208385031215613f0b57600080fd5b823567ffffffffffffffff80821115613f2357600080fd5b818501915085601f830112613f3757600080fd5b813581811115613f4657600080fd5b8660208260051b8501011115613f5b57600080fd5b60209290920196919550909350505050565b60005b83811015613f88578181015183820152602001613f70565b838111156118d45750506000910152565b60008151808452613fb1816020860160208601613f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614044858351613f99565b9450928501929085019060010161400a565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561408357600080fd5b8a3561408e81613b71565b995060208b013561409e81613b71565b985060408b01356140ae81613b71565b975060608b0135965060808b013595506140ca60a08c01613d84565b94506140d860c08c01613d84565b93506140e660e08c01613a07565b92506140f56101008c01613a07565b91506101208b013567ffffffffffffffff81111561411257600080fd5b61411e8d828e01613b06565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561414a5761414a613a3b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261418757600080fd5b8135614195613b2782614130565b8181528460208386010111156141aa57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156141dd57600080fd5b84356141e881613b71565b93506141f660208601613d84565b925061420460408601613a07565b9150606085013567ffffffffffffffff81111561422057600080fd5b61422c87828801614176565b91505092959194509250565b6000806040838503121561424b57600080fd5b823561425681613b71565b9150602083013561426681613b71565b809150509250929050565b6000806000806000806000806000806000806101808d8f03121561429457600080fd5b61429d8d613b93565b9b506142ab60208e01613b93565b9a506142b960408e01613b93565b995060608d0135985060808d0135975060a08d0135965060c08d013595506142e360e08e01613d84565b94506142f26101008e01613d84565b93506143016101208e01613d84565b92506143106101408e01613a07565b915067ffffffffffffffff6101608e0135111561432c57600080fd5b61433d8e6101608f01358f01614176565b90509295989b509295989b509295989b565b60006020828403121561436157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff838116908316818110156143b4576143b4614368565b039392505050565b600063ffffffff8083168185168083038211156143db576143db614368565b01949350505050565b600063ffffffff8083168181036143fd576143fd614368565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261446b57600080fd5b83018035915067ffffffffffffffff82111561448657600080fd5b6020019150368190038213156135ef57600080fd5b8183823760009101908152919050565b6000602082840312156144bd57600080fd5b815167ffffffffffffffff8111156144d457600080fd5b8201601f810184136144e557600080fd5b80516144f3613b2782614130565b81815285602083850101111561450857600080fd5b612772826020830160208601613f6d565b602081526000612bfb6020830184613f99565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455d5761455d614368565b5060010190565b67ffffffffffffffff83168152604060208201526000612bf86040830184613f99565b60006020828403121561459957600080fd5b8151612bfb81613b71565b600081518084526020808501945080840160005b838110156145d4578151875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145d457815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145f3565b85815260a06020820152600061463e60a08301876145a4565b73ffffffffffffffffffffffffffffffffffffffff8087166040850152838203606085015261466d82876145df565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c08301516146f860c084018267ffffffffffffffff169052565b5060e083015161471460e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff8083168185168083038211156143db576143db614368565b60008282101561475f5761475f614368565b500390565b6000821982111561477757614777614368565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526147ac60e08401826145a4565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261277282826145df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485557614855614817565b500490565b60008261486957614869614817565b500690565b60006020828403121561488057600080fd5b8151612bfb81613d34565b600067ffffffffffffffff838116908316818110156143b4576143b4614368565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148e4576148e4614368565b500290565b600082516148fb818460208701613f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212209da4bba922e72e8a4d613325bde7422470ee1aea7d82220d65f7da5c44f56f0c64736f6c634300080d0033", "devdoc": { diff --git a/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 43633ef5..9303e25d 100644 --- a/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/optimism/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon-mumbai/MintableERC1155.json b/deployments/polygon-mumbai/MintableERC1155.json index bb32035d..e66d2b31 100644 --- a/deployments/polygon-mumbai/MintableERC1155.json +++ b/deployments/polygon-mumbai/MintableERC1155.json @@ -511,7 +511,7 @@ "args": [], "numDeployments": 3, "solcInputHash": "200193942e0f09d7ebb5ccce1bc305e7", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\ncontract MintableERC1155 is ERC1155, Ownable {\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x1ce6820f23820d4d6dbd48b168e6de51efe1216c4880e2f2e0bb3143d58d7ed5\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\ncontract MintableERC1155 is ERC1155, Ownable {\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x1ce6820f23820d4d6dbd48b168e6de51efe1216c4880e2f2e0bb3143d58d7ed5\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080346200012657602081016001600160401b03811182821017620001105760405260008091526002546001908181811c9116801562000105575b6020821014620000f157601f8111620000a7575b600283905560038054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08680a3611fc990816200012c8239f35b60028352601f0160051c7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace908101905b818110620000e657506200004e565b8381558201620000d7565b634e487b7160e01b83526022600452602483fd5b90607f16906200003a565b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea26469706673582212204649af28b2218246749413731aaab257fc72268b5a9c227716987edfd17c6b3e64736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea26469706673582212204649af28b2218246749413731aaab257fc72268b5a9c227716987edfd17c6b3e64736f6c63430008120033", "devdoc": { diff --git a/deployments/polygon-mumbai/PolygonTokenBridger.json b/deployments/polygon-mumbai/PolygonTokenBridger.json index bf0831dd..9f71acea 100644 --- a/deployments/polygon-mumbai/PolygonTokenBridger.json +++ b/deployments/polygon-mumbai/PolygonTokenBridger.json @@ -219,7 +219,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon-mumbai/Polygon_SpokePool.json b/deployments/polygon-mumbai/Polygon_SpokePool.json index d8a9d979..c8dbfc13 100644 --- a/deployments/polygon-mumbai/Polygon_SpokePool.json +++ b/deployments/polygon-mumbai/Polygon_SpokePool.json @@ -1227,7 +1227,7 @@ ], "numDeployments": 1, "solcInputHash": "c2d6025a634518ca1feda7b98c45d21d", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790556007805460ff60a01b191690553480156200003457600080fd5b5060405162004cee38038062004cee833981016040819052620000579162000238565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055848484836200008784620000d7565b62000092836200017d565b506001600160a01b03908116608052600780549982166001600160a01b03199a8b161790556006805495909116949098169390931790965550620002cc945050505050565b6001600160a01b038116620001335760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001d55760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c206164647265737300000000000000000000000060448201526064016200012a565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b6001600160a01b03811681146200023557600080fd5b50565b60008060008060008060c087890312156200025257600080fd5b86516200025f816200021f565b602088015190965062000272816200021f565b604088015190955062000285816200021f565b606088015190945062000298816200021f565b6080880151909350620002ab816200021f565b60a0880151909250620002be816200021f565b809150509295509295509295565b6080516149dc620003126000396000818161021c01528181610e6b01528181610f3401528181611ef10152818161276d0152818161308301526130d901526149dc6000f3fe6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json b/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json index 8f32c282..cb04c7ce 100644 --- a/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json +++ b/deployments/polygon-mumbai/solcInputs/200193942e0f09d7ebb5ccce1bc305e7.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json b/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json index 78455c1b..042e6dae 100644 --- a/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json +++ b/deployments/polygon-mumbai/solcInputs/2a98e0c4f048f0fda1d4cc9162127646.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @dev Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n *\n * NOTE: Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\ncontract MintableERC1155 is ERC1155, Ownable {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @dev Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n *\n * NOTE: Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json b/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json index bb0f1a27..127623b2 100644 --- a/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json +++ b/deployments/polygon-mumbai/solcInputs/c0d608dcade73b41bfb146ca48293092.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\ncontract MintableERC1155 is ERC1155PresetMinterPauser {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256[] amounts);\n\n constructor() ERC1155PresetMinterPauser(\"\") {}\n\n /**\n * @dev Creates `amounts[i]` new tokens for `recipients[i]` of toke type `tokenId`.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256[] memory amounts\n ) public {\n require(recipients.length == amounts.length, \"MintableERC1155: recipients and amounts length mismatch\");\n\n for (uint256 i = 0; i < recipients.length; i++) {\n mint(recipients[i], tokenId, amounts[i], \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amounts);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to set uri\");\n\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for token types.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol\";\n\ncontract MintableERC1155 is ERC1155PresetMinterPauser {\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256[] amounts);\n\n constructor() ERC1155PresetMinterPauser(\"\") {}\n\n /**\n * @dev Creates `amounts[i]` new tokens for `recipients[i]` of toke type `tokenId`.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256[] memory amounts\n ) public {\n require(recipients.length == amounts.length, \"MintableERC1155: recipients and amounts length mismatch\");\n\n for (uint256 i = 0; i < recipients.length; i++) {\n mint(recipients[i], tokenId, amounts[i], \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amounts);\n }\n\n /**\n * @dev Sets the URI for token of type `tokenId` to `tokenURI`.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to set uri\");\n\n _tokenURIs[tokenId] = tokenURI;\n }\n\n /**\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for token types.\n */\n function uri(uint256 tokenId) public view virtual override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/presets/ERC1155PresetMinterPauser.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC1155.sol\";\nimport \"../extensions/ERC1155Burnable.sol\";\nimport \"../extensions/ERC1155Pausable.sol\";\nimport \"../../../access/AccessControlEnumerable.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev {ERC1155} token, including:\n *\n * - ability for holders to burn (destroy) their tokens\n * - a minter role that allows for token minting (creation)\n * - a pauser role that allows to stop all token transfers\n *\n * This contract uses {AccessControl} to lock permissioned functions using the\n * different roles - head to its documentation for details.\n *\n * The account that deploys the contract will be granted the minter and pauser\n * roles, as well as the default admin role, which will let it grant both minter\n * and pauser roles to other accounts.\n *\n * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._\n */\ncontract ERC1155PresetMinterPauser is Context, AccessControlEnumerable, ERC1155Burnable, ERC1155Pausable {\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n /**\n * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, and `PAUSER_ROLE` to the account that\n * deploys the contract.\n */\n constructor(string memory uri) ERC1155(uri) {\n _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());\n\n _setupRole(MINTER_ROLE, _msgSender());\n _setupRole(PAUSER_ROLE, _msgSender());\n }\n\n /**\n * @dev Creates `amount` new tokens for `to`, of token type `id`.\n *\n * See {ERC1155-_mint}.\n *\n * Requirements:\n *\n * - the caller must have the `MINTER_ROLE`.\n */\n function mint(\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) public virtual {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to mint\");\n\n _mint(to, id, amount, data);\n }\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.\n */\n function mintBatch(\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) public virtual {\n require(hasRole(MINTER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have minter role to mint\");\n\n _mintBatch(to, ids, amounts, data);\n }\n\n /**\n * @dev Pauses all token transfers.\n *\n * See {ERC1155Pausable} and {Pausable-_pause}.\n *\n * Requirements:\n *\n * - the caller must have the `PAUSER_ROLE`.\n */\n function pause() public virtual {\n require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have pauser role to pause\");\n _pause();\n }\n\n /**\n * @dev Unpauses all token transfers.\n *\n * See {ERC1155Pausable} and {Pausable-_unpause}.\n *\n * Requirements:\n *\n * - the caller must have the `PAUSER_ROLE`.\n */\n function unpause() public virtual {\n require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC1155PresetMinterPauser: must have pauser role to unpause\");\n _unpause();\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId)\n public\n view\n virtual\n override(AccessControlEnumerable, ERC1155)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n function _beforeTokenTransfer(\n address operator,\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual override(ERC1155, ERC1155Pausable) {\n super._beforeTokenTransfer(operator, from, to, ids, amounts, data);\n }\n}\n" diff --git a/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json b/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json index a0cc1d52..2a6425e5 100644 --- a/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json +++ b/deployments/polygon-mumbai/solcInputs/c2d6025a634518ca1feda7b98c45d21d.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -107,7 +107,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -116,43 +116,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Optimism_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Exact copy of the Optimism_SpokePool with no modifications.\r\n */\r\ncontract Boba_SpokePool is Optimism_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n ) Optimism_SpokePool(_crossDomainAdmin, _hubPool, timerAddress) {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -161,22 +161,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/MintableERC1155.json b/deployments/polygon/MintableERC1155.json index 77928bc6..b53bda8f 100644 --- a/deployments/polygon/MintableERC1155.json +++ b/deployments/polygon/MintableERC1155.json @@ -511,7 +511,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "ea9229ed188f1300c4a413d030dbf1b6", - "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"title\":\"MintableERC1155\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"notice\":\"Ownable contract enabling owner to airdrop many recipients the same token ID at once\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\n/**\\n * @title MintableERC1155\\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\\n */\\ncontract MintableERC1155 is ERC1155, Ownable {\\n // Maps `tokenId` to metadata URI `tokenURI`\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\\n // to allow for IPFS URIs.\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x3278a4a107e88bf5a9c63672ea4fb33f5e7fa86e2c089f73bafa681eb6bc3641\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Airdrop\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_tokenURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"airdrop\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"setTokenURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"details\":\"Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\",\"params\":{\"amount\":\"Amount of token types to airdrop.\",\"recipients\":\"List of airdrop recipients.\",\"tokenId\":\"Token type to airdrop.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"setTokenURI(uint256,string)\":{\"params\":{\"tokenId\":\"Token type to set `tokenURI` for.\",\"tokenURI\":\"URI of token metadata.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"Instead of returning the same URI for *all* token types, we return the uri set by `setTokenURI` to allow IPFS URIs for all token types.\",\"params\":{\"tokenId\":\"Token type to retrieve metadata URI for.\"}}},\"title\":\"MintableERC1155\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"airdrop(uint256,address[],uint256)\":{\"notice\":\"Creates `amount` new tokens for `recipients` of token type `tokenId`.\"},\"setTokenURI(uint256,string)\":{\"notice\":\"Sets the URI for token of type `tokenId` to `tokenURI`.\"},\"uri(uint256)\":{\"notice\":\"Returns metadata URI of token type `tokenId`.\"}},\"notice\":\"Ownable contract enabling owner to airdrop many recipients the same token ID at once\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/erc1155/MintableERC1155.sol\":\"MintableERC1155\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner nor approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0x447a21c87433c0f11252912313a96f3454629ef88cca7a4eefbb283b3ec409f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"contracts/erc1155/MintableERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\n\\n/**\\n * @title MintableERC1155\\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\\n */\\ncontract MintableERC1155 is ERC1155, Ownable {\\n // Maps `tokenId` to metadata URI `tokenURI`\\n mapping(uint256 => string) public _tokenURIs;\\n\\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\\n\\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\\n // to allow for IPFS URIs.\\n // solhint-disable-next-line\\n constructor() ERC1155(\\\"\\\") {}\\n\\n /**\\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\\n * @param recipients List of airdrop recipients.\\n * @param tokenId Token type to airdrop.\\n * @param amount Amount of token types to airdrop.\\n */\\n function airdrop(\\n uint256 tokenId,\\n address[] memory recipients,\\n uint256 amount\\n ) public onlyOwner {\\n for (uint256 i = 0; i < recipients.length; i++) {\\n _mint(recipients[i], tokenId, amount, \\\"\\\");\\n }\\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\\n }\\n\\n /**\\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\\n * @param tokenId Token type to set `tokenURI` for.\\n * @param tokenURI URI of token metadata.\\n */\\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\\n require(bytes(_tokenURIs[tokenId]).length == 0, \\\"uri already set\\\");\\n\\n _tokenURIs[tokenId] = tokenURI;\\n emit URI(tokenURI, tokenId);\\n }\\n\\n /**\\n * @notice Returns metadata URI of token type `tokenId`.\\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\\n * `setTokenURI` to allow IPFS URIs for all token types.\\n * @param tokenId Token type to retrieve metadata URI for.\\n */\\n function uri(uint256 tokenId) public view override returns (string memory) {\\n return _tokenURIs[tokenId];\\n }\\n}\\n\",\"keccak256\":\"0x3278a4a107e88bf5a9c63672ea4fb33f5e7fa86e2c089f73bafa681eb6bc3641\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x6080346200012657602081016001600160401b03811182821017620001105760405260008091526002546001908181811c9116801562000105575b6020821014620000f157601f8111620000a7575b600283905560038054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08680a3611fc990816200012c8239f35b60028352601f0160051c7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace908101905b818110620000e657506200004e565b8381558201620000d7565b634e487b7160e01b83526022600452602483fd5b90607f16906200003a565b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea2646970667358221220c3377770cdb03b603ff928387edb7dc3ad004b20210900a98759b0565733980764736f6c63430008120033", "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e146116c957806301ffc9a7146115da5780630bb78ec1146115815780630e89341c14611581578063162094c4146112b25780632eb2c2d614610ef65780634e1273f414610d44578063715018a614610ca3578063754e5e37146107e15780638da5cb5b1461078e578063a22cb4651461063a578063e985e9c5146105bd578063f242432a146101f55763f2fde38b146100ba57600080fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576100f1611717565b906100fa611af0565b73ffffffffffffffffffffffffffffffffffffffff80921692831561016e575050600354827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8280fd5b5090346101f15760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15761022e611717565b8361023761173f565b916044359060643560843567ffffffffffffffff81116105b95761025e9036908901611a23565b9273ffffffffffffffffffffffffffffffffffffffff80931692338414801561059a575b61028b90611ccc565b861690610299821515611d57565b6102a281611f5d565b506102ac83611f5d565b50808652602096868852888720858852885283898820546102cf82821015611de2565b838952888a528a8920878a528a52038988205581875286885288872083885288528887206102fe858254611e6d565b905582858a51848152868b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628c3392a43b61033a578580f35b889587946103948a51978896879586947ff23a6e61000000000000000000000000000000000000000000000000000000009c8d8752339087015260248601526044850152606484015260a0608484015260a48301906118ea565b03925af186918161056b575b506104af5750506001906103b2611eb2565b6308c379a014610462575b506103d25750505b3880808381808080808580f35b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b0390fd5b61046a611ed0565b8061047557506103bd565b61045e859185519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff00000000000000000000000000000000000000000000000000000000160390506104df5750506103c5565b61045e9250519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b61058c919250843d8611610593575b61058481836117b5565b810190611e7a565b90386103a0565b503d61057a565b508386526001602090815288872033885290528786205460ff16610282565b8480fd5b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760ff816020936105fb611717565b61060361173f565b73ffffffffffffffffffffffffffffffffffffffff91821683526001875283832091168252855220549151911615158152f35b5080fd5b5090346101f157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610672611717565b90602435918215158093036105b95773ffffffffffffffffffffffffffffffffffffffff169283331461070c575033845260016020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c2073746174757360448201527f20666f722073656c6600000000000000000000000000000000000000000000006064820152fd5b50503461063657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106365760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5090346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781359260249067ffffffffffffffff908235828111610636576108389036908701611a41565b9560448035610845611af0565b835b8951811015610c175773ffffffffffffffffffffffffffffffffffffffff61086f828c611c89565b51168851906020918281018181108a821117610bec578b528781528115610b6a57858c92898c8a948f6108a187611f5d565b506108ab8b611f5d565b5086845283895280842085855289528084206108c88c8254611e6d565b9055848482518981528d8c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4843b610919575b50505050505050505061091490611c2d565b610847565b916109748493928a9796959351988997889687957ff23a6e61000000000000000000000000000000000000000000000000000000009d8e885233908801528601528401528c606484015260a0608484015260a48301906118ea565b03925af1889181610b4b575b50610a8d575050600190610992611eb2565b6308c379a014610a41575b506109b557610914905b9089858538898c828f610902565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e204552433131353560408201527f526563656976657220696d706c656d656e74657200000000000000000000000060608201520190565b610a49611ed0565b80610a54575061099d565b61045e8c918b8d519485947f08c379a00000000000000000000000000000000000000000000000000000000086528501528301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016039050610abf57610914906109a7565b61045e8989519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a6563746560408201527f6420746f6b656e7300000000000000000000000000000000000000000000000060608201520190565b610b63919250843d86116105935761058481836117b5565b9038610980565b5050897f455243313135353a206d696e7420746f20746865207a65726f206164647265738560218b6084958e51957f08c379a00000000000000000000000000000000000000000000000000000000087528601528401528201527f73000000000000000000000000000000000000000000000000000000000000006064820152fd5b8a8960418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b89858984878251926080808501913386526020938487015285015285518091528160a08501960191855b828110610c7957867f13d0a346ea6c350592dd539c68d5ff6d61d6b8834695625d09834638717193e087808b8960608301520390a180f35b835173ffffffffffffffffffffffffffffffffffffffff1688529681019692810192600101610c41565b8334610d4157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d4157610cda611af0565b8073ffffffffffffffffffffffffffffffffffffffff6003547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b509134610d4157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610d415767ffffffffffffffff83358181116101f157610d939036908601611a41565b906024359081116101f157610dab90369086016119c5565b938151855103610e7357508051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610dfb610de6856119ad565b94610df3875196876117b5565b8086526119ad565b013660208501375b8151811015610e5a5780610e4573ffffffffffffffffffffffffffffffffffffffff610e32610e559486611c89565b5116610e3e8389611c89565b5190611b6f565b610e4f8286611c89565b52611c2d565b610e03565b835160208082528190610e6f90820186611abc565b0390f35b60849060208551917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152fd5b50346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9160a0833601126112ae57610f30611717565b92610f3961173f565b9367ffffffffffffffff936044358581116112aa57610f5b90369083016119c5565b906064358681116112a657610f7390369083016119c5565b956084359081116112a657610f8b9036908301611a23565b9373ffffffffffffffffffffffffffffffffffffffff809416933385148015611287575b610fb890611ccc565b835188510361120457881694610fcf861515611d57565b895b8a85518210156110555790896110498a61105094610ffa85610ff3818d611c89565b5195611c89565b51938082526020908282528383208d84528252858d858520549061102083831015611de2565b838652858552868620908652845203848420558252818152828220908d83525220918254611e6d565b9055611c2d565b610fd1565b50509094939596929197848789518a81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6110938c830188611abc565b918083036020820152806110a833948b611abc565b0390a43b6110b4578880f35b865194859384937fbc197c810000000000000000000000000000000000000000000000000000000098898652338c87015260248601526044850160a0905260a485016110ff91611abc565b8285820301606486015261111291611abc565b90838203016084840152611125916118ea565b0381885a94602095f18591816111e4575b506111b65750506001611147611eb2565b6308c379a014611165575b6103d25750505b38808080808080808880f35b61116d611ed0565b806111785750611152565b905061045e9160209450519384937f08c379a000000000000000000000000000000000000000000000000000000000855284015260248301906118ea565b7fffffffff0000000000000000000000000000000000000000000000000000000016036104df575050611159565b6111fd91925060203d81116105935761058481836117b5565b9038611136565b60848360208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060448201527f6d69736d617463680000000000000000000000000000000000000000000000006064820152fd5b50848a5260016020908152878b20338c529052868a205460ff16610faf565b8880fd5b8780fd5b8380fd5b50346101f157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15780359167ffffffffffffffff9060243582811161157d573660238201121561157d576113169036906024818701359101611948565b9261131f611af0565b84865260209281845261133483882054611762565b611521578587528184528287209185519182116114f557506113568254611762565b601f81116114b2575b5083601f82116001146113ef5791817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b969594926113de948a916113e4575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b519282849384528301906118ea565b0390a280f35b90508601513861139e565b828852848820907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316895b81811061149b5750926113de9492600192827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b9a99989610611464575b5050811b0190556113cf565b8801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880611458565b91928760018192868c01518155019401920161141b565b828852848820601f830160051c8101918684106114eb575b601f0160051c01905b8181106114e0575061135f565b8881556001016114d3565b90915081906114ca565b8760416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b508260649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600f60248201527f75726920616c72656164792073657400000000000000000000000000000000006044820152fd5b8580fd5b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15781610e6f93826115c79335825260205220611825565b90519182916020835260208301906118ea565b50346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602092507fd9b67a2600000000000000000000000000000000000000000000000000000000821491821561169f575b8215611675575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491503861166c565b7f0e89341c0000000000000000000000000000000000000000000000000000000081149250611665565b50503461063657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261063657602090611710611707611717565b60243590611b6f565b9051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361173a57565b90600182811c921680156117ab575b602083101461177c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611771565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117f657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b906040519182600082549261183984611762565b9081845260019485811690816000146118a85750600114611865575b5050611863925003836117b5565b565b9093915060005260209081600020936000915b81831061189057505061186393508201013880611855565b85548884018501529485019487945091830191611878565b90506118639550602093507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013880611855565b919082519283825260005b8481106119345750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016118f5565b92919267ffffffffffffffff82116117f6576040519161199060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117b5565b82948184528183011161173a578281602093846000960137010152565b67ffffffffffffffff81116117f65760051b60200190565b81601f8201121561173a578035916119dc836119ad565b926119ea60405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a14575050505090565b81358152908301908301611a06565b9080601f8301121561173a57816020611a3e93359101611948565b90565b81601f8201121561173a57803591611a58836119ad565b92611a6660405194856117b5565b808452602092838086019260051b82010192831161173a578301905b828210611a90575050505090565b813573ffffffffffffffffffffffffffffffffffffffff8116810361173a578152908301908301611a82565b90815180825260208080930193019160005b828110611adc575050505090565b835185529381019392810192600101611ace565b73ffffffffffffffffffffffffffffffffffffffff600354163303611b1157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b73ffffffffffffffffffffffffffffffffffffffff16908115611ba957600052600060205260406000209060005260205260406000205490565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201527f616c6964206f776e6572000000000000000000000000000000000000000000006064820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c5a5760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8051821015611c9d5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b15611cd357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201527f6572206e6f7220617070726f76656400000000000000000000000000000000006064820152fd5b15611d5e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152fd5b15611de957565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201527f72207472616e73666572000000000000000000000000000000000000000000006064820152fd5b91908201809211611c5a57565b9081602091031261173a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361173a5790565b60009060033d11611ebf57565b905060046000803e60005160e01c90565b600060443d10611a3e576040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91823d016004833e815167ffffffffffffffff918282113d602484011117611f4c57818401948551938411611f54573d85010160208487010111611f4c5750611a3e929101602001906117b5565b949350505050565b50949350505050565b604051906040820182811067ffffffffffffffff8211176117f65760405260018252602082016020368237825115611c9d57529056fea2646970667358221220c3377770cdb03b603ff928387edb7dc3ad004b20210900a98759b0565733980764736f6c63430008120033", "devdoc": { diff --git a/deployments/polygon/PolygonTokenBridger.json b/deployments/polygon/PolygonTokenBridger.json index 1da54729..9106e24a 100644 --- a/deployments/polygon/PolygonTokenBridger.json +++ b/deployments/polygon/PolygonTokenBridger.json @@ -219,7 +219,7 @@ ], "numDeployments": 2, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract PolygonRegistry\",\"name\":\"_l1PolygonRegistry\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WrappedMatic\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l1ChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"callExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1PolygonRegistry\",\"outputs\":[{\"internalType\":\"contract PolygonRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WrappedMatic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"callExit(bytes)\":{\"params\":{\"data\":\"the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\"}},\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1ChainId\":\"the chain id for the L1 in this environment.\",\"_l1PolygonRegistry\":\"L1 registry that stores updated addresses of polygon contracts. This should always be set to the L1 registry regardless if whether it's deployed on L2 or L1.\",\"_l1Weth\":\"L1 WETH address.\",\"_l2ChainId\":\"the chain id for the L2 in this environment.\",\"_l2WrappedMatic\":\"L2 address of wrapped matic token.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"callExit(bytes)\":{\"notice\":\"Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\"},\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x61014060405234801561001157600080fd5b506040516200122f3803806200122f83398101604081905261003291610087565b6000805460ff191660011790556001600160a01b0395861660805293851660a05291841660c05290921660e05261010091909152610120526100fa565b6001600160a01b038116811461008457600080fd5b50565b60008060008060008060c087890312156100a057600080fd5b86516100ab8161006f565b60208801519096506100bc8161006f565b60408801519095506100cd8161006f565b60608801519094506100de8161006f565b809350506080870151915060a087015190509295509295509295565b60805160a05160c05160e05161010051610120516110ae620001816000396000818161027101526106c501526000818160f5015281816102e0015261051a01526000818161019501526107f701526000818161013c0152818161030a015261035d0152600081816101c9015261054601526000818161021d015261040f01526110ae6000f3fe6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b55760003560e01c80637ffae68811610069578063d0679d341161004e578063d0679d341461023f578063d6ae3cd51461025f578063dc3542961461029357600080fd5b80637ffae688146101eb578063b269681d1461020b57600080fd5b8063146bf4b11161009a578063146bf4b11461012a57806344516d861461018357806368f38248146101b757600080fd5b80630a79309b146100c157806312622e5b146100e357600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004610e34565b6102a9565b005b3480156100ef57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561013657600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b34801561018f57600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c357600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101f757600080fd5b506100e1610206366004610e80565b6104e3565b34801561021757600080fd5b5061015e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561024b57600080fd5b506100e161025a366004610f4f565b61068e565b34801561026b57600080fd5b506101177f000000000000000000000000000000000000000000000000000000000000000081565b34801561029f57600080fd5b5061015e61101081565b6102b16108eb565b6102de600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006103088161095e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103dd577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103c357600080fd5b505af11580156103d7573d6000803e3d6000fd5b50505050505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104af907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8516906370a0823190602401602060405180830381865afa15801561046d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104919190610f7b565b73ffffffffffffffffffffffffffffffffffffffff851691906109c7565b506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b6104eb6108eb565b610518600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006105428161095e565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b68649766040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190610f94565b6040517f7c5264b400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690637c5264b49061062a908690600401611027565b600060405180830381600087803b15801561064457600080fd5b505af1158015610658573d6000803e3d6000fd5b5050505050506104e0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6106966108eb565b6106c3600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7f00000000000000000000000000000000000000000000000000000000000000006106ed8161095e565b61070f73ffffffffffffffffffffffffffffffffffffffff8416333085610aa0565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a59190610f7b565b6040518263ffffffff1660e01b81526004016107c391815260200190565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108b6576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247600482015261101090632e1a7d4d9047906024016000604051808303818588803b15801561089c57600080fd5b505af11580156108b0573d6000803e3d6000fd5b50505050505b506108e7600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b60005460ff1661095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b8046146104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f742072756e206d6574686f64206f6e207468697320636861696e006044820152606401610953565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a9b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610b04565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610afe9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610a19565b50505050565b6000610b66826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610c109092919063ffffffff16565b805190915015610a9b5780806020019051810190610b84919061103a565b610a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610953565b6060610c1f8484600085610c29565b90505b9392505050565b606082471015610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610953565b73ffffffffffffffffffffffffffffffffffffffff85163b610d39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610953565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610d62919061105c565b60006040518083038185875af1925050503d8060008114610d9f576040519150601f19603f3d011682016040523d82523d6000602084013e610da4565b606091505b5091509150610db4828286610dbf565b979650505050505050565b60608315610dce575081610c22565b825115610dde5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109539190611027565b73ffffffffffffffffffffffffffffffffffffffff811681146104e057600080fd5b600060208284031215610e4657600080fd5b8135610c2281610e12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e9257600080fd5b813567ffffffffffffffff80821115610eaa57600080fd5b818401915084601f830112610ebe57600080fd5b813581811115610ed057610ed0610e51565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610f1657610f16610e51565b81604052828152876020848701011115610f2f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060408385031215610f6257600080fd5b8235610f6d81610e12565b946020939093013593505050565b600060208284031215610f8d57600080fd5b5051919050565b600060208284031215610fa657600080fd5b8151610c2281610e12565b60005b83811015610fcc578181015183820152602001610fb4565b83811115610afe5750506000910152565b60008151808452610ff5816020860160208601610fb1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c226020830184610fdd565b60006020828403121561104c57600080fd5b81518015158114610c2257600080fd5b6000825161106e818460208701610fb1565b919091019291505056fea264697066735822122063ecc081c16c759e25d3706decc185c2b87de3cddb24340f1f5ab7ea9090f16464736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon/Polygon_SpokePool.json b/deployments/polygon/Polygon_SpokePool.json index 5fbea7ea..5e66b209 100644 --- a/deployments/polygon/Polygon_SpokePool.json +++ b/deployments/polygon/Polygon_SpokePool.json @@ -1227,7 +1227,7 @@ ], "numDeployments": 1, "solcInputHash": "55c0117eb9fb2209b6f60673be44d9d8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"_polygonTokenBridger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainAdmin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wmaticAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_fxChild\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"appliedRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PolygonTokensBridged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"SetFxChild\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"polygonTokenBridger\",\"type\":\"address\"}],\"name\":\"SetPolygonTokenBridger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fxChild\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"polygonTokenBridger\",\"outputs\":[{\"internalType\":\"contract PolygonTokenBridger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rootMessageSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"processMessageFromRoot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFxChild\",\"type\":\"address\"}],\"name\":\"setFxChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPolygonTokenBridger\",\"type\":\"address\"}],\"name\":\"setPolygonTokenBridger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_crossDomainAdmin\":\"Cross domain admin to set. Can be changed by admin.\",\"_fxChild\":\"FxChild contract, changeable by Admin.\",\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_polygonTokenBridger\":\"Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\",\"_wmaticAddress\":\"Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"details\":\"this is only overridden to wrap any matic the contract holds before running.\",\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call wrap before running the function.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"processMessageFromRoot(uint256,address,bytes)\":{\"details\":\"stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync triggered this call.\",\"params\":{\"data\":\"ABI encoded function call to execute on this contract.\",\"rootMessageSender\":\"Original L1 sender of data.\"}},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setFxChild(address)\":{\"params\":{\"newFxChild\":\"New FxChild.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"setPolygonTokenBridger(address)\":{\"params\":{\"newPolygonTokenBridger\":\"New Polygon Token Bridger contract.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"wrap()\":{\"details\":\"Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping must be done via a separate transaction.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Polygon SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"processMessageFromRoot(uint256,address,bytes)\":{\"notice\":\"Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check that the L1 caller was the expected cross domain admin, and then delegate calls.Polygon bridge only executes this external function on the target Polygon contract when relaying messages from L1, so all functions on this SpokePool are expected to originate via this call.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setFxChild(address)\":{\"notice\":\"Change FxChild address. Callable only by admin via processMessageFromRoot.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"setPolygonTokenBridger(address)\":{\"notice\":\"Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"},\"wrap()\":{\"notice\":\"Allows the caller to trigger the wrapping of any unwrapped matic tokens.\"}},\"notice\":\"Polygon specific SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Polygon_SpokePool.sol\":\"Polygon_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// Polygon Registry contract that stores their addresses.\\r\\ninterface PolygonRegistry {\\r\\n function erc20Predicate() external returns (address);\\r\\n}\\r\\n\\r\\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\\r\\ninterface PolygonERC20Predicate {\\r\\n function startExitWithBurntTokens(bytes calldata data) external;\\r\\n}\\r\\n\\r\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\r\\ninterface PolygonIERC20 is IERC20 {\\r\\n function withdraw(uint256 amount) external;\\r\\n}\\r\\n\\r\\ninterface MaticToken {\\r\\n function withdraw(uint256 amount) external payable;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\r\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\r\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\r\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\r\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\r\\n * mechanism from normal create.\\r\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\r\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\r\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\r\\n * sender.\\r\\n */\\r\\ncontract PolygonTokenBridger is Lockable {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n // Gas token for Polygon.\\r\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\r\\n\\r\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\r\\n address public immutable destination;\\r\\n\\r\\n // Registry that stores L1 polygon addresses.\\r\\n PolygonRegistry public immutable l1PolygonRegistry;\\r\\n\\r\\n // WETH contract on Ethereum.\\r\\n WETH9 public immutable l1Weth;\\r\\n\\r\\n // Wrapped Matic on Polygon\\r\\n address public immutable l2WrappedMatic;\\r\\n\\r\\n // Chain id for the L1 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the mainnet chainId 1.\\r\\n uint256 public immutable l1ChainId;\\r\\n\\r\\n // Chain id for the L2 that this contract is deployed on or communicates with.\\r\\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\\r\\n // the polygon chainId 137.\\r\\n uint256 public immutable l2ChainId;\\r\\n\\r\\n modifier onlyChainId(uint256 chainId) {\\r\\n _requireChainId(chainId);\\r\\n _;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Constructs Token Bridger contract.\\r\\n * @param _destination Where to send tokens to for this network.\\r\\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\\r\\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\\r\\n * @param _l1Weth L1 WETH address.\\r\\n * @param _l2WrappedMatic L2 address of wrapped matic token.\\r\\n * @param _l1ChainId the chain id for the L1 in this environment.\\r\\n * @param _l2ChainId the chain id for the L2 in this environment.\\r\\n */\\r\\n constructor(\\r\\n address _destination,\\r\\n PolygonRegistry _l1PolygonRegistry,\\r\\n WETH9 _l1Weth,\\r\\n address _l2WrappedMatic,\\r\\n uint256 _l1ChainId,\\r\\n uint256 _l2ChainId\\r\\n ) {\\r\\n destination = _destination;\\r\\n l1PolygonRegistry = _l1PolygonRegistry;\\r\\n l1Weth = _l1Weth;\\r\\n l2WrappedMatic = _l2WrappedMatic;\\r\\n l1ChainId = _l1ChainId;\\r\\n l2ChainId = _l2ChainId;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\r\\n * @notice The caller of this function must approve this contract to spend amount of token.\\r\\n * @param token Token to bridge.\\r\\n * @param amount Amount to bridge.\\r\\n */\\r\\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\\r\\n token.safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\r\\n token.withdraw(token.balanceOf(address(this)));\\r\\n\\r\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\r\\n if (address(token) == l2WrappedMatic)\\r\\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\r\\n * @param token Token to send to destination.\\r\\n */\\r\\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\\r\\n if (address(token) == address(l1Weth)) {\\r\\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\\r\\n l1Weth.deposit{ value: address(this).balance }();\\r\\n }\\r\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\\r\\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\\r\\n */\\r\\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\\r\\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\\r\\n erc20Predicate.startExitWithBurntTokens(data);\\r\\n }\\r\\n\\r\\n receive() external payable {\\r\\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\\r\\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\\r\\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\\r\\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\\r\\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\\r\\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\\r\\n // sent to the contract.\\r\\n }\\r\\n\\r\\n function _requireChainId(uint256 chainId) internal view {\\r\\n require(block.chainid == chainId, \\\"Cannot run method on this chain\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xe0e716e187b6e37842eabfc3229815fa74b95365c82a069c9dd473309cafe267\",\"license\":\"AGPL-3.0-only\"},\"contracts/Polygon_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./SpokePool.sol\\\";\\r\\nimport \\\"./PolygonTokenBridger.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\n\\r\\n// IFxMessageProcessor represents interface to process messages.\\r\\ninterface IFxMessageProcessor {\\r\\n function processMessageFromRoot(\\r\\n uint256 stateId,\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\\r\\n/**\\r\\n * @notice Polygon specific SpokePool.\\r\\n */\\r\\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\\r\\n using SafeERC20 for PolygonIERC20;\\r\\n\\r\\n // Address of FxChild which sends and receives messages to and from L1.\\r\\n address public fxChild;\\r\\n\\r\\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\\r\\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\\r\\n PolygonTokenBridger public polygonTokenBridger;\\r\\n\\r\\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\\r\\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\\r\\n bool private callValidated = false;\\r\\n\\r\\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\\r\\n event SetFxChild(address indexed newFxChild);\\r\\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\\r\\n\\r\\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\\r\\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\\r\\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\\r\\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\\r\\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\\r\\n modifier validateInternalCalls() {\\r\\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\\r\\n // processMessageFromRoot from being re-entered.\\r\\n require(!callValidated, \\\"callValidated already set\\\");\\r\\n\\r\\n // This sets a variable indicating that we're now inside a validated call.\\r\\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\\r\\n // spoofed. See\\r\\n callValidated = true;\\r\\n\\r\\n _;\\r\\n\\r\\n // Reset callValidated to false to disallow admin calls after this method exits.\\r\\n callValidated = false;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Construct the Polygon SpokePool.\\r\\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\\r\\n * @param _fxChild FxChild contract, changeable by Admin.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n PolygonTokenBridger _polygonTokenBridger,\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\\r\\n address _fxChild,\\r\\n address timerAddress\\r\\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\\r\\n polygonTokenBridger = _polygonTokenBridger;\\r\\n fxChild = _fxChild;\\r\\n }\\r\\n\\r\\n /********************************************************\\r\\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\\r\\n ********************************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newFxChild New FxChild.\\r\\n */\\r\\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\\r\\n fxChild = newFxChild;\\r\\n emit SetFxChild(newFxChild);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\\r\\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\\r\\n */\\r\\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\\r\\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\\r\\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\\r\\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\\r\\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\\r\\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\\r\\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\\r\\n * triggered this call.\\r\\n * @param rootMessageSender Original L1 sender of data.\\r\\n * @param data ABI encoded function call to execute on this contract.\\r\\n */\\r\\n function processMessageFromRoot(\\r\\n uint256, /*stateId*/\\r\\n address rootMessageSender,\\r\\n bytes calldata data\\r\\n ) public validateInternalCalls {\\r\\n // Validation logic.\\r\\n require(msg.sender == fxChild, \\\"Not from fxChild\\\");\\r\\n require(rootMessageSender == crossDomainAdmin, \\\"Not from mainnet admin\\\");\\r\\n\\r\\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\\r\\n (bool success, ) = address(this).delegatecall(data);\\r\\n require(success, \\\"delegatecall failed\\\");\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\\r\\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\\r\\n * must be done via a separate transaction.\\r\\n */\\r\\n function wrap() public nonReentrant {\\r\\n _wrap();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @dev this is only overridden to wrap any matic the contract holds before running.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public override nonReentrant {\\r\\n _wrap();\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\\r\\n * wrap before running the function.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _wrap();\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\r\\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\\r\\n address(polygonTokenBridger),\\r\\n relayerRefundLeaf.amountToReturn\\r\\n );\\r\\n\\r\\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\\r\\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\\r\\n\\r\\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\\r\\n }\\r\\n\\r\\n function _wrap() internal {\\r\\n uint256 balance = address(this).balance;\\r\\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\\r\\n }\\r\\n\\r\\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\\r\\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\\r\\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\\r\\n // `processMessageFromRoot`.\\r\\n function _requireAdminSender() internal view override {\\r\\n require(callValidated, \\\"Must call processMessageFromRoot\\\");\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9ba4af990c273cac7eb1693b8ee6fdf6480d70fb30a7d72ee846c814ee88485c\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 appliedRelayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint256 length = relayerRefundLeaf.refundAmounts.length;\\r\\n for (uint256 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint256).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 appliedRelayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayData.relayerFeePct,\\r\\n appliedRelayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0x3fbc30406d04eb43f3525d04035ad63cda5bd900a931d86badad1eb8914472e5\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\r\\n */\\r\\ninterface SpokePoolInterface {\\r\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\r\\n struct RelayerRefundLeaf {\\r\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\r\\n // is negative. This is just the negative of this value.\\r\\n uint256 amountToReturn;\\r\\n // Used to verify that this is being executed on the correct destination chainId.\\r\\n uint256 chainId;\\r\\n // This array designates how much each of those addresses should be refunded.\\r\\n uint256[] refundAmounts;\\r\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\r\\n uint32 leafId;\\r\\n // The associated L2TokenAddress that these claims apply to.\\r\\n address l2TokenAddress;\\r\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\r\\n address[] refundAddresses;\\r\\n }\\r\\n\\r\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\r\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\r\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\r\\n // chain validator can choose when to refund slow relayers.\\r\\n struct RelayData {\\r\\n // The address that made the deposit on the origin chain.\\r\\n address depositor;\\r\\n // The recipient address on the destination chain.\\r\\n address recipient;\\r\\n // The corresponding token address on the destination chain.\\r\\n address destinationToken;\\r\\n // The total relay amount before fees are taken out.\\r\\n uint256 amount;\\r\\n // Origin chain id.\\r\\n uint256 originChainId;\\r\\n // Destination chain id.\\r\\n uint256 destinationChainId;\\r\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\r\\n // and the HubPool's utilization.\\r\\n uint64 realizedLpFeePct;\\r\\n // The relayer fee percentage specified in the deposit.\\r\\n uint64 relayerFeePct;\\r\\n // The id uniquely identifying this deposit on the origin chain.\\r\\n uint32 depositId;\\r\\n }\\r\\n\\r\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\r\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\r\\n struct RootBundle {\\r\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\r\\n bytes32 slowRelayRoot;\\r\\n // Merkle root of relayer refunds for successful relays.\\r\\n bytes32 relayerRefundRoot;\\r\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\r\\n // 256x(2^248) leaves per root.\\r\\n mapping(uint256 => uint256) claimedBitmap;\\r\\n }\\r\\n\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\r\\n\\r\\n function setHubPool(address newHubPool) external;\\r\\n\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enable\\r\\n ) external;\\r\\n\\r\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\r\\n\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\r\\n\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\r\\n\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) external payable;\\r\\n\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) external;\\r\\n\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) external;\\r\\n\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) external;\\r\\n\\r\\n function chainId() external view returns (uint256);\\r\\n}\\r\\n\",\"keccak256\":\"0x3561cccf209e77555f8384b7cc92c4bc9355b2755d94e68f770d76579da11336\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790556007805460ff60a01b191690553480156200003457600080fd5b5060405162004cee38038062004cee833981016040819052620000579162000238565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055848484836200008784620000d7565b62000092836200017d565b506001600160a01b03908116608052600780549982166001600160a01b03199a8b161790556006805495909116949098169390931790965550620002cc945050505050565b6001600160a01b038116620001335760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001d55760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c206164647265737300000000000000000000000060448201526064016200012a565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b6001600160a01b03811681146200023557600080fd5b50565b60008060008060008060c087890312156200025257600080fd5b86516200025f816200021f565b602088015190965062000272816200021f565b604088015190955062000285816200021f565b606088015190945062000298816200021f565b6080880151909350620002ab816200021f565b60a0880151909250620002be816200021f565b809150509295509295509295565b6080516149dc620003126000396000818161021c01528181610e6b01528181610f3401528181611ef10152818161276d0152818161308301526130d901526149dc6000f3fe6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101dc5760003560e01c806357f6dcb811610102578063be3576ee11610095578063e282d5b911610064578063e282d5b914610615578063ee2a53f814610635578063f06850f61461066a578063ffc351a31461069757600080fd5b8063be3576ee14610593578063d46eb119146105b3578063de7eba78146105c8578063e1904402146105e857600080fd5b80639a8a0592116100d15780639a8a059214610507578063a1244c671461051a578063ac9650d814610553578063b86cfdcf1461057357600080fd5b806357f6dcb81461045d57806389a153cc146104a75780638a7860ce146104c75780639a7c4b71146104e757600080fd5b80632752042e1161017a578063492289781161014957806349228978146103b2578063493a4f84146103c55780635249fef1146103e55780635285e0581461043057600080fd5b80632752042e1461031557806329cb924d146103355780633edb89d114610358578063450d11f01461038557600080fd5b80631c39c38d116101b65780631c39c38d146102885780631dfb2d02146102b557806322f8e566146102d5578063272751c7146102f557600080fd5b806313fb77ee146101e857806317fcb39b1461020a5780631b3d55591461026857600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613a68565b6106b7565b005b34801561021657600080fd5b5061023e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027457600080fd5b50610208610283366004613c43565b6107a7565b34801561029457600080fd5b5060005461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c157600080fd5b506102086102d0366004613a68565b610838565b3480156102e157600080fd5b506102086102f0366004613d3f565b6108c2565b34801561030157600080fd5b50610208610310366004613d66565b61096b565b34801561032157600080fd5b50610208610330366004613da8565b610a7d565b34801561034157600080fd5b5061034a610b7e565b60405190815260200161025f565b34801561036457600080fd5b5060075461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561039157600080fd5b5060065461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b6102086103c0366004613ddb565b610c36565b3480156103d157600080fd5b506102086103e0366004613e45565b6110ad565b3480156103f157600080fd5b50610420610400366004613e67565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161025f565b34801561043c57600080fd5b5060015461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561046957600080fd5b506002546104929074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161025f565b3480156104b357600080fd5b506102086104c2366004613e93565b6111c7565b3480156104d357600080fd5b506102086104e2366004613d3f565b611323565b3480156104f357600080fd5b50610208610502366004613f37565b6113f7565b34801561051357600080fd5b504661034a565b34801561052657600080fd5b50600254610492907801000000000000000000000000000000000000000000000000900463ffffffff1681565b610566610561366004613fc0565b6116c5565b60405161025f91906140ab565b34801561057f57600080fd5b5061020861058e366004613a68565b61189f565b34801561059f57600080fd5b506102086105ae36600461412b565b61198c565b3480156105bf57600080fd5b50610208611a20565b3480156105d457600080fd5b506102086105e3366004613a68565b611aa3565b3480156105f457600080fd5b5060025461023e9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561062157600080fd5b5061020861063036600461428f565b611ae9565b34801561064157600080fd5b50610655610650366004613d3f565b611c47565b6040805192835260208301919091520161025f565b34801561067657600080fd5b5061034a610685366004613d3f565b60056020526000908152604090205481565b3480156106a357600080fd5b506102086106b2366004614300565b611c75565b6106bf611de0565b6106c7611e64565b6106f4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f6ade7bc58132776cc11d9b570837a732329396078de17b87db95463ca7f5d25f90600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b6107af611e64565b6107dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6107e4611ee8565b6107ef838383611f6b565b610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b610840611de0565b610848611e64565b610875600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612317565b6107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff166108e457600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b15801561095057600080fd5b505af1158015610964573d6000803e3d6000fd5b5050505050565b610973611de0565b61097b611e64565b6109a8600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a3610833600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610a85611de0565b610a8d611e64565b610aba600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a16107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610c315760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c91906143de565b905090565b504290565b610c3e611e64565b610c6b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610d85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b600254610db09074010000000000000000000000000000000000000000900463ffffffff1682614426565b63ffffffff16610dbe610b7e565b10158015610e035750600254610df29074010000000000000000000000000000000000000000900463ffffffff168261444b565b63ffffffff16610e00610b7e565b11155b610e69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610ec45750600034115b15610fb857833414610f32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610d01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9a57600080fd5b505af1158015610fae573d6000803e3d6000fd5b5050505050610fda565b610fda73ffffffffffffffffffffffffffffffffffffffff8616333087612403565b6110118446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d336124df565b60028054601890611043907801000000000000000000000000000000000000000000000000900463ffffffff16614473565b91906101000a81548163ffffffff021916908363ffffffff1602179055506110a5600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b6110b5611de0565b6110bd611e64565b6110ea600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a450506111c3600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b6111cf611e64565b6111fc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016112714690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006112ad82612570565b905060006112bf82848b8860006125a0565b90506112d082828a8887600061284d565b505050611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b61132b611de0565b611333611e64565b611360600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061137357611373614496565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60075474010000000000000000000000000000000000000000900460ff161561147c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f63616c6c56616c69646174656420616c726561647920736574000000000000006044820152606401610d01565b600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556006543373ffffffffffffffffffffffffffffffffffffffff9091161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f742066726f6d2066784368696c64000000000000000000000000000000006044820152606401610d01565b60015473ffffffffffffffffffffffffffffffffffffffff8481169116146115c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f742066726f6d206d61696e6e65742061646d696e000000000000000000006044820152606401610d01565b60003073ffffffffffffffffffffffffffffffffffffffff1683836040516115eb9291906144c5565b600060405180830381855af49150503d8060008114611626576040519150601f19603f3d011682016040523d82523d6000602084013e61162b565b606091505b5050905080611696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f64656c656761746563616c6c206661696c6564000000000000000000000000006044820152606401610d01565b5050600780547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055505050565b6060341561172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610d01565b8167ffffffffffffffff81111561174857611748613a9e565b60405190808252806020026020018201604052801561177b57816020015b60608152602001906001900390816117665790505b50905060005b82811015611898576000803086868581811061179f5761179f614496565b90506020028101906117b191906144d5565b6040516117bf9291906144c5565b600060405180830381855af49150503d80600081146117fa576040519150601f19603f3d011682016040523d82523d6000602084013e6117ff565b606091505b5091509150816118655760448151101561181857600080fd5b60048101905080806020019051810190611832919061453a565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b8084848151811061187857611878614496565b602002602001018190525050508080611890906145bb565b915050611781565b5092915050565b6118a7611de0565b6118af611e64565b6118dc600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f573834b6d6901b74ef64eeb676a0b99d7946df822b7021e44ee0da19d846c49590600090a26107a4600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611994611e64565b6119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6119c9611ee8565b6119dc8a8a8a8a8a468b8b8b8b8b61298f565b611317600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611a28611e64565b611a55600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611a5d611ee8565b611aa1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b565b611aab611de0565b611ab3611e64565b611ae0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61087e81612b0e565b611af1611e64565b611b1e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff1610611b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610d01565b611ba68446858585612bfa565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d378584604051611bf59291906145f3565b60405180910390a3611c41600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b60038181548110611c5757600080fd5b60009182526020909120600390910201805460019091015490915082565b611c7d611e64565b611caa600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b611cb78c87858585612bfa565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8152602001888152602001611d2c4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff1681525090506000611d6882612570565b90506000611d7a82848d8960006125a0565b9050611d8b82828c8987600061284d565b505050611dd2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60075474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742063616c6c2070726f636573734d65737361676546726f6d526f6f746044820152606401610d01565b60005474010000000000000000000000000000000000000000900460ff16611aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d01565b4780156107a4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611f5757600080fd5b505af11580156110a5573d6000803e3d6000fd5b46826020015114611fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610d01565b8160400151518260a00151511461204b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610d01565b600060038463ffffffff168154811061206657612066614496565b9060005260206000209060030201905061208581600101548484612c97565b6120eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610d01565b61210281600201846060015163ffffffff16612cd4565b15612169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610d01565b61218081600201846060015163ffffffff16612d15565b60408301515160005b81811015612211576000856040015182815181106121a9576121a9614496565b602002602001015190506000811115612208576122088660a0015183815181106121d5576121d5614496565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50600101612189565b508351156122aa5761222284612da9565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f718760000151336040516122a192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051612308959493929190614697565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610d01565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611c419085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612edd565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b60008160405160200161258391906146f5565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156125d857506706f05b59d3b200008560c0015167ffffffffffffffff16105b61263e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610d01565b6060850151600087815260056020526040902054106126b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610d01565b836000036126c957506000612844565b6126e284848760c001516126dd919061479c565b612fe9565b6000878152600560205260408120546060880151929350869261270591906147bf565b90508281101561272e5780925061272b83868960c00151612726919061479c565b613023565b91505b6000888152600560205260408120805485929061274c9084906147d6565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036127d457836127c15760408701516127c19073ffffffffffffffffffffffffffffffffffffffff16333085612403565b6127cf87602001518361304c565b612841565b8361280e576127cf338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16612403909392919063ffffffff16565b612841876020015183896040015173ffffffffffffffffffffffffffffffffffffffff16612d539092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f56450a30040c51955338a4a9fbafcf94f7ca4b75f4cd83c2f5e29ef77fbe0a3a8460600151600560008b815260200190815260200160002054898988608001518960a001518a60e001518c8c60c001518d61010001518e604001518f602001518f60405161297f9d9c9b9a999897969594939291909c8d5260208d019b909b5260408c019990995260608b019790975260808a019590955260a089019390935267ffffffffffffffff91821660c0890152811660e08801521661010086015263ffffffff1661012085015273ffffffffffffffffffffffffffffffffffffffff9081166101408501521661016083015215156101808201526101a00190565b60405180910390a3505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff168152509050612a6460038463ffffffff1681548110612a4b57612a4b614496565b906000526020600020906003020160000154828461318d565b612aca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610d01565b6000612ad582612570565b90506000612aec82848560600151600060016125a0565b9050612afe828260008087600161284d565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610d01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e0016040516020818303038152906040528051906020012090506000612c81826131a5565b9050612c8e8782856131e0565b50505050505050565b6000612cca828585604051602001612caf91906147ee565b6040516020818303038152906040528051906020012061327e565b90505b9392505050565b600080612ce3610100846148b8565b90506000612cf3610100856148cc565b6000928352602095909552506040902054600190931b92831690921492915050565b6000612d23610100836148b8565b90506000612d33610100846148cc565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108339084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161245d565b60075481516080830151612dd89273ffffffffffffffffffffffffffffffffffffffff91821692911690613294565b600754608082015182516040517fd0679d3400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063d0679d3490604401600060405180830381600087803b158015612e5357600080fd5b505af1158015612e67573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff16816080015173ffffffffffffffffffffffffffffffffffffffff167ff6003d597c8a5b43987488bd11bfd2ed0c5a14172ae0f7ce18894e7b004915be8360000151604051612ed291815260200190565b60405180910390a350565b6000612f3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166133929092919063ffffffff16565b8051909150156108335780806020019051810190612f5d91906148e0565b610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d01565b6000612ffd82670de0b6b3a76400006148fd565b67ffffffffffffffff1661301984670de0b6b3a764000061491e565b612ccd91906148b8565b6000670de0b6b3a764000061303883826148fd565b6130199067ffffffffffffffff168561491e565b73ffffffffffffffffffffffffffffffffffffffff82163b156130aa576111c373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383612d53565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561313257600080fd5b505af1158015613146573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f19350505050158015610833573d6000803e3d6000fd5b6000612cca828585604051602001612caf91906146f5565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612583565b6131ea82826133a1565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610d01565b60008261328b85846133c5565b14949350505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f91906143de565b61333991906147d6565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260448101829052909150611c419085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161245d565b6060612cca8484600085613431565b60008060006133b085856135c7565b915091506133bd81613635565b509392505050565b600081815b84518110156133bd5760008582815181106133e7576133e7614496565b6020026020010151905080831161340d576000838152602082905260409020925061341e565b600081815260208490526040902092505b5080613429816145bb565b9150506133ca565b6060824710156134c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d01565b73ffffffffffffffffffffffffffffffffffffffff85163b613541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d01565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161356a919061495b565b60006040518083038185875af1925050503d80600081146135a7576040519150601f19603f3d011682016040523d82523d6000602084013e6135ac565b606091505b50915091506135bc828286613889565b979650505050505050565b60008082516041036135fd5760208301516040840151606085015160001a6135f1878285856138dc565b9450945050505061362e565b8251604003613626576020830151604084015161361b8683836139f4565b93509350505061362e565b506000905060025b9250929050565b600081600481111561364957613649614977565b036136515750565b600181600481111561366557613665614977565b036136cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610d01565b60028160048111156136e0576136e0614977565b03613747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d01565b600381600481111561375b5761375b614977565b036137e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60048160048111156137fc576137fc614977565b036107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610d01565b60608315613898575081612ccd565b8251156138a85782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0191906145a8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561391357506000905060036139eb565b8460ff16601b1415801561392b57508460ff16601c14155b1561393c57506000905060046139eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613990573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166139e4576000600192509250506139eb565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831681613a2a60ff86901c601b6147d6565b9050613a38878288856138dc565b935093505050935093915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107a457600080fd5b600060208284031215613a7a57600080fd5b8135612ccd81613a46565b803563ffffffff81168114613a9957600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613af057613af0613a9e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b3d57613b3d613a9e565b604052919050565b600067ffffffffffffffff821115613b5f57613b5f613a9e565b5060051b60200190565b600082601f830112613b7a57600080fd5b81356020613b8f613b8a83613b45565b613af6565b82815260059290921b84018101918181019086841115613bae57600080fd5b8286015b84811015613bc95780358352918301918301613bb2565b509695505050505050565b8035613a9981613a46565b600082601f830112613bf057600080fd5b81356020613c00613b8a83613b45565b82815260059290921b84018101918181019086841115613c1f57600080fd5b8286015b84811015613bc9578035613c3681613a46565b8352918301918301613c23565b600080600060608486031215613c5857600080fd5b613c6184613a85565b9250602084013567ffffffffffffffff80821115613c7e57600080fd5b9085019060c08288031215613c9257600080fd5b613c9a613acd565b8235815260208301356020820152604083013582811115613cba57600080fd5b613cc689828601613b69565b604083015250613cd860608401613a85565b6060820152613ce960808401613bd4565b608082015260a083013582811115613d0057600080fd5b613d0c89828601613bdf565b60a08301525093506040860135915080821115613d2857600080fd5b50613d3586828701613b69565b9150509250925092565b600060208284031215613d5157600080fd5b5035919050565b80151581146107a457600080fd5b600080600060608486031215613d7b57600080fd5b8335613d8681613a46565b9250602084013591506040840135613d9d81613d58565b809150509250925092565b600060208284031215613dba57600080fd5b612ccd82613a85565b803567ffffffffffffffff81168114613a9957600080fd5b60008060008060008060c08789031215613df457600080fd5b8635613dff81613a46565b95506020870135613e0f81613a46565b94506040870135935060608701359250613e2b60808801613dc3565b9150613e3960a08801613a85565b90509295509295509295565b60008060408385031215613e5857600080fd5b50508035926020909101359150565b60008060408385031215613e7a57600080fd5b8235613e8581613a46565b946020939093013593505050565b6000806000806000806000806000806101408b8d031215613eb357600080fd5b8a35613ebe81613a46565b995060208b0135613ece81613a46565b985060408b0135613ede81613a46565b975060608b0135965060808b0135955060a08b0135945060c08b01359350613f0860e08c01613dc3565b9250613f176101008c01613dc3565b9150613f266101208c01613a85565b90509295989b9194979a5092959850565b60008060008060608587031215613f4d57600080fd5b843593506020850135613f5f81613a46565b9250604085013567ffffffffffffffff80821115613f7c57600080fd5b818701915087601f830112613f9057600080fd5b813581811115613f9f57600080fd5b886020828501011115613fb157600080fd5b95989497505060200194505050565b60008060208385031215613fd357600080fd5b823567ffffffffffffffff80821115613feb57600080fd5b818501915085601f830112613fff57600080fd5b81358181111561400e57600080fd5b8660208260051b850101111561402357600080fd5b60209290920196919550909350505050565b60005b83811015614050578181015183820152602001614038565b83811115611c415750506000910152565b60008151808452614079816020860160208601614035565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561411e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261410c858351614061565b945092850192908501906001016140d2565b5092979650505050505050565b6000806000806000806000806000806101408b8d03121561414b57600080fd5b8a3561415681613a46565b995060208b013561416681613a46565b985060408b013561417681613a46565b975060608b0135965060808b0135955061419260a08c01613dc3565b94506141a060c08c01613dc3565b93506141ae60e08c01613a85565b92506141bd6101008c01613a85565b91506101208b013567ffffffffffffffff8111156141da57600080fd5b6141e68d828e01613b69565b9150509295989b9194979a5092959850565b600067ffffffffffffffff82111561421257614212613a9e565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261424f57600080fd5b813561425d613b8a826141f8565b81815284602083860101111561427257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156142a557600080fd5b84356142b081613a46565b93506142be60208601613dc3565b92506142cc60408601613a85565b9150606085013567ffffffffffffffff8111156142e857600080fd5b6142f48782880161423e565b91505092959194509250565b6000806000806000806000806000806000806101808d8f03121561432357600080fd5b61432c8d613bd4565b9b5061433a60208e01613bd4565b9a5061434860408e01613bd4565b995060608d0135985060808d0135975060a08d0135965060c08d0135955061437260e08e01613dc3565b94506143816101008e01613dc3565b93506143906101208e01613dc3565b925061439f6101408e01613a85565b915067ffffffffffffffff6101608e013511156143bb57600080fd5b6143cc8e6101608f01358f0161423e565b90509295989b509295989b509295989b565b6000602082840312156143f057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015614443576144436143f7565b039392505050565b600063ffffffff80831681851680830382111561446a5761446a6143f7565b01949350505050565b600063ffffffff80831681810361448c5761448c6143f7565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261450a57600080fd5b83018035915067ffffffffffffffff82111561452557600080fd5b60200191503681900382131561362e57600080fd5b60006020828403121561454c57600080fd5b815167ffffffffffffffff81111561456357600080fd5b8201601f8101841361457457600080fd5b8051614582613b8a826141f8565b81815285602083850101111561459757600080fd5b612844826020830160208601614035565b602081526000612ccd6020830184614061565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145ec576145ec6143f7565b5060010190565b67ffffffffffffffff83168152604060208201526000612cca6040830184614061565b600081518084526020808501945080840160005b838110156146465781518752958201959082019060010161462a565b509495945050505050565b600081518084526020808501945080840160005b8381101561464657815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614665565b85815260a0602082015260006146b060a0830187614616565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526146df8287614651565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161476a60c084018267ffffffffffffffff169052565b5060e083015161478660e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff80831681851680830382111561446a5761446a6143f7565b6000828210156147d1576147d16143f7565b500390565b600082198211156147e9576147e96143f7565b500190565b6020815281516020820152602082015160408201526000604083015160c0606084015261481e60e0840182614616565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c08501526128448282614651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826148c7576148c7614889565b500490565b6000826148db576148db614889565b500690565b6000602082840312156148f257600080fd5b8151612ccd81613d58565b600067ffffffffffffffff83811690831681811015614443576144436143f7565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614956576149566143f7565b500290565b6000825161496d818460208701614035565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220d6e35905856520494fe7a1cc4236a7012bdf1bb998c26080dc32f4ccfbf8e85664736f6c634300080d0033", "devdoc": { diff --git a/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json b/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json index 43633ef5..9303e25d 100644 --- a/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json +++ b/deployments/polygon/solcInputs/55c0117eb9fb2209b6f60673be44d9d8.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\r\n\r\n/**\r\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\r\n * to be consumed by off-chain bots, rather than by other contracts.\r\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\r\n * system of the full contract suite..\r\n */\r\ncontract AcrossConfigStore is Ownable, MultiCaller {\r\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\r\n // Transfer Thresholds.\r\n mapping(address => string) public l1TokenConfig;\r\n\r\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\r\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\r\n mapping(bytes32 => string) public globalConfig;\r\n\r\n event UpdatedTokenConfig(address indexed key, string value);\r\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\r\n\r\n /**\r\n * @notice Updates token config.\r\n * @param l1Token the l1 token address to update value for.\r\n * @param value Value to update.\r\n */\r\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\r\n l1TokenConfig[l1Token] = value;\r\n emit UpdatedTokenConfig(l1Token, value);\r\n }\r\n\r\n /**\r\n * @notice Updates global config.\r\n * @param key Key to update.\r\n * @param value Value to update.\r\n */\r\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\r\n globalConfig[key] = value;\r\n emit UpdatedGlobalConfig(key, value);\r\n }\r\n}\r\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -23,73 +23,73 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\r\n\r\n/**\r\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\r\n */\r\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\r\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\r\n // unused by bridge but included for future compatibility.\r\n uint32 public l1Gas = 5_000_000;\r\n\r\n // ETH is an ERC20 on OVM.\r\n address public immutable l2Eth;\r\n\r\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\r\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\r\n mapping(address => address) public tokenBridges;\r\n\r\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\r\n event SetL1Gas(uint32 indexed newL1Gas);\r\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\r\n\r\n /**\r\n * @notice Construct the OVM SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _l2Eth,\r\n address _wrappedNativeToken,\r\n address timerAddress\r\n )\r\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\r\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\r\n {\r\n l2Eth = _l2Eth;\r\n }\r\n\r\n /*******************************************\r\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\r\n *******************************************/\r\n\r\n /**\r\n * @notice Change L1 gas limit. Callable only by admin.\r\n * @param newl1Gas New L1 gas limit to set.\r\n */\r\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\r\n l1Gas = newl1Gas;\r\n emit SetL1Gas(newl1Gas);\r\n }\r\n\r\n /**\r\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\r\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\r\n * @param tokenBridge Address of token bridge\r\n */\r\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\r\n tokenBridges[l2Token] = tokenBridge;\r\n emit SetL2TokenBridge(l2Token, tokenBridge);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 totalRelayAmount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n totalRelayAmount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\r\n * ETH over the canonical token bridge instead of WETH.\r\n * @inheritdoc SpokePool\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override(SpokePool) nonReentrant {\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\r\n\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\r\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\r\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\r\n // on the OVM.\r\n function _depositEthToWeth() internal {\r\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\r\n }\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\r\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\r\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\r\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\r\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\r\n }\r\n IL2ERC20Bridge(\r\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\r\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\r\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\r\n ).withdrawTo(\r\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\r\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\r\n relayerRefundLeaf.amountToReturn, // _amount.\r\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\r\n \"\" // _data. We don't need to send any data for the bridging action.\r\n );\r\n\r\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\r\n }\r\n\r\n // Apply OVM-specific transformation to cross domain admin address on L1.\r\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\r\n}\r\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,13 +104,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Optimism Spoke pool.\r\n */\r\ncontract Optimism_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Optimism SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n Lib_PredeployAddresses.OVM_ETH,\r\n 0x4200000000000000000000000000000000000006,\r\n timerAddress\r\n )\r\n {}\r\n}\r\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -119,43 +119,43 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\r\n * that excludes the custom bridging logic.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Boba.\r\n * @param target Contract on Boba that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Boba.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Ovm_SpokePool.sol\";\r\n\r\n/**\r\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\r\n */\r\ncontract Boba_SpokePool is Ovm_SpokePool {\r\n /**\r\n * @notice Construct the OVM Boba SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address timerAddress\r\n )\r\n Ovm_SpokePool(\r\n _crossDomainAdmin,\r\n _hubPool,\r\n timerAddress,\r\n 0x4200000000000000000000000000000000000006,\r\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000\r\n )\r\n {}\r\n}\r\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -164,22 +164,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json b/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json index a9377e90..74e62cf1 100644 --- a/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json +++ b/deployments/polygon/solcInputs/b20d5afcf396996ae08652b8281973a7.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 appliedRelayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint256 length = relayerRefundLeaf.refundAmounts.length;\r\n for (uint256 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint256).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 appliedRelayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayData.relayerFeePct,\r\n appliedRelayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @notice Contains common data structures and functions used by all SpokePool implementations.\r\n */\r\ninterface SpokePoolInterface {\r\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\r\n struct RelayerRefundLeaf {\r\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\r\n // is negative. This is just the negative of this value.\r\n uint256 amountToReturn;\r\n // Used to verify that this is being executed on the correct destination chainId.\r\n uint256 chainId;\r\n // This array designates how much each of those addresses should be refunded.\r\n uint256[] refundAmounts;\r\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\r\n uint32 leafId;\r\n // The associated L2TokenAddress that these claims apply to.\r\n address l2TokenAddress;\r\n // Must be same length as refundAmounts and designates each address that must be refunded.\r\n address[] refundAddresses;\r\n }\r\n\r\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\r\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\r\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\r\n // chain validator can choose when to refund slow relayers.\r\n struct RelayData {\r\n // The address that made the deposit on the origin chain.\r\n address depositor;\r\n // The recipient address on the destination chain.\r\n address recipient;\r\n // The corresponding token address on the destination chain.\r\n address destinationToken;\r\n // The total relay amount before fees are taken out.\r\n uint256 amount;\r\n // Origin chain id.\r\n uint256 originChainId;\r\n // Destination chain id.\r\n uint256 destinationChainId;\r\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\r\n // and the HubPool's utilization.\r\n uint64 realizedLpFeePct;\r\n // The relayer fee percentage specified in the deposit.\r\n uint64 relayerFeePct;\r\n // The id uniquely identifying this deposit on the origin chain.\r\n uint32 depositId;\r\n }\r\n\r\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\r\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\r\n struct RootBundle {\r\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\r\n bytes32 slowRelayRoot;\r\n // Merkle root of relayer refunds for successful relays.\r\n bytes32 relayerRefundRoot;\r\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\r\n // 256x(2^248) leaves per root.\r\n mapping(uint256 => uint256) claimedBitmap;\r\n }\r\n\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\r\n\r\n function setHubPool(address newHubPool) external;\r\n\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enable\r\n ) external;\r\n\r\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\r\n\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\r\n\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\r\n\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) external payable;\r\n\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) external;\r\n\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) external;\r\n\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) external;\r\n\r\n function chainId() external view returns (uint256);\r\n}\r\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./Lockable.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// Polygon Registry contract that stores their addresses.\r\ninterface PolygonRegistry {\r\n function erc20Predicate() external returns (address);\r\n}\r\n\r\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\r\ninterface PolygonERC20Predicate {\r\n function startExitWithBurntTokens(bytes calldata data) external;\r\n}\r\n\r\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\r\ninterface PolygonIERC20 is IERC20 {\r\n function withdraw(uint256 amount) external;\r\n}\r\n\r\ninterface MaticToken {\r\n function withdraw(uint256 amount) external payable;\r\n}\r\n\r\n/**\r\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\r\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\r\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\r\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\r\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\r\n * mechanism from normal create.\r\n * Normal create: address = hash(deployer_address, deployer_nonce)\r\n * create2: address = hash(0xFF, sender, salt, bytecode)\r\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\r\n * sender.\r\n */\r\ncontract PolygonTokenBridger is Lockable {\r\n using SafeERC20 for PolygonIERC20;\r\n using SafeERC20 for IERC20;\r\n\r\n // Gas token for Polygon.\r\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\r\n\r\n // Should be set to HubPool on Ethereum, or unused on Polygon.\r\n address public immutable destination;\r\n\r\n // Registry that stores L1 polygon addresses.\r\n PolygonRegistry public immutable l1PolygonRegistry;\r\n\r\n // WETH contract on Ethereum.\r\n WETH9 public immutable l1Weth;\r\n\r\n // Wrapped Matic on Polygon\r\n address public immutable l2WrappedMatic;\r\n\r\n // Chain id for the L1 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the mainnet chainId 1.\r\n uint256 public immutable l1ChainId;\r\n\r\n // Chain id for the L2 that this contract is deployed on or communicates with.\r\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\r\n // the polygon chainId 137.\r\n uint256 public immutable l2ChainId;\r\n\r\n modifier onlyChainId(uint256 chainId) {\r\n _requireChainId(chainId);\r\n _;\r\n }\r\n\r\n /**\r\n * @notice Constructs Token Bridger contract.\r\n * @param _destination Where to send tokens to for this network.\r\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\r\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\r\n * @param _l1Weth L1 WETH address.\r\n * @param _l2WrappedMatic L2 address of wrapped matic token.\r\n * @param _l1ChainId the chain id for the L1 in this environment.\r\n * @param _l2ChainId the chain id for the L2 in this environment.\r\n */\r\n constructor(\r\n address _destination,\r\n PolygonRegistry _l1PolygonRegistry,\r\n WETH9 _l1Weth,\r\n address _l2WrappedMatic,\r\n uint256 _l1ChainId,\r\n uint256 _l2ChainId\r\n ) {\r\n destination = _destination;\r\n l1PolygonRegistry = _l1PolygonRegistry;\r\n l1Weth = _l1Weth;\r\n l2WrappedMatic = _l2WrappedMatic;\r\n l1ChainId = _l1ChainId;\r\n l2ChainId = _l2ChainId;\r\n }\r\n\r\n /**\r\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\r\n * @notice The caller of this function must approve this contract to spend amount of token.\r\n * @param token Token to bridge.\r\n * @param amount Amount to bridge.\r\n */\r\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\r\n token.safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\r\n token.withdraw(token.balanceOf(address(this)));\r\n\r\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\r\n if (address(token) == l2WrappedMatic)\r\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\r\n }\r\n\r\n /**\r\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\r\n * @param token Token to send to destination.\r\n */\r\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\r\n if (address(token) == address(l1Weth)) {\r\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\r\n l1Weth.deposit{ value: address(this).balance }();\r\n }\r\n token.safeTransfer(destination, token.balanceOf(address(this)));\r\n }\r\n\r\n /**\r\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\r\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\r\n */\r\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\r\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\r\n erc20Predicate.startExitWithBurntTokens(data);\r\n }\r\n\r\n receive() external payable {\r\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\r\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\r\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\r\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\r\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\r\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\r\n // sent to the contract.\r\n }\r\n\r\n function _requireChainId(uint256 chainId) internal view {\r\n require(block.chainid == chainId, \"Cannot run method on this chain\");\r\n }\r\n}\r\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./SpokePool.sol\";\r\nimport \"./PolygonTokenBridger.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n// IFxMessageProcessor represents interface to process messages.\r\ninterface IFxMessageProcessor {\r\n function processMessageFromRoot(\r\n uint256 stateId,\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Polygon specific SpokePool.\r\n */\r\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\r\n using SafeERC20 for PolygonIERC20;\r\n\r\n // Address of FxChild which sends and receives messages to and from L1.\r\n address public fxChild;\r\n\r\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\r\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\r\n PolygonTokenBridger public polygonTokenBridger;\r\n\r\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\r\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\r\n bool private callValidated = false;\r\n\r\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\r\n event SetFxChild(address indexed newFxChild);\r\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\r\n\r\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\r\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\r\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\r\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\r\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\r\n modifier validateInternalCalls() {\r\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\r\n // processMessageFromRoot from being re-entered.\r\n require(!callValidated, \"callValidated already set\");\r\n\r\n // This sets a variable indicating that we're now inside a validated call.\r\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\r\n // spoofed. See\r\n callValidated = true;\r\n\r\n _;\r\n\r\n // Reset callValidated to false to disallow admin calls after this method exits.\r\n callValidated = false;\r\n }\r\n\r\n /**\r\n * @notice Construct the Polygon SpokePool.\r\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\r\n * @param _fxChild FxChild contract, changeable by Admin.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n PolygonTokenBridger _polygonTokenBridger,\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\r\n address _fxChild,\r\n address timerAddress\r\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\r\n polygonTokenBridger = _polygonTokenBridger;\r\n fxChild = _fxChild;\r\n }\r\n\r\n /********************************************************\r\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\r\n ********************************************************/\r\n\r\n /**\r\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\r\n * @param newFxChild New FxChild.\r\n */\r\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\r\n fxChild = newFxChild;\r\n emit SetFxChild(newFxChild);\r\n }\r\n\r\n /**\r\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\r\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\r\n */\r\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\r\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\r\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\r\n }\r\n\r\n /**\r\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\r\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\r\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\r\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\r\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\r\n * triggered this call.\r\n * @param rootMessageSender Original L1 sender of data.\r\n * @param data ABI encoded function call to execute on this contract.\r\n */\r\n function processMessageFromRoot(\r\n uint256, /*stateId*/\r\n address rootMessageSender,\r\n bytes calldata data\r\n ) public validateInternalCalls {\r\n // Validation logic.\r\n require(msg.sender == fxChild, \"Not from fxChild\");\r\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\r\n\r\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\r\n (bool success, ) = address(this).delegatecall(data);\r\n require(success, \"delegatecall failed\");\r\n }\r\n\r\n /**\r\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\r\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\r\n * must be done via a separate transaction.\r\n */\r\n function wrap() public nonReentrant {\r\n _wrap();\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @dev this is only overridden to wrap any matic the contract holds before running.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public override nonReentrant {\r\n _wrap();\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\r\n * wrap before running the function.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _wrap();\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\r\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\r\n address(polygonTokenBridger),\r\n relayerRefundLeaf.amountToReturn\r\n );\r\n\r\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\r\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\r\n\r\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\r\n }\r\n\r\n function _wrap() internal {\r\n uint256 balance = address(this).balance;\r\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\r\n }\r\n\r\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\r\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\r\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\r\n // `processMessageFromRoot`.\r\n function _requireAdminSender() internal view override {\r\n require(callValidated, \"Must call processMessageFromRoot\");\r\n }\r\n}\r\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\r\n// this contract's state variables to be `immutable` because of the delegateCall call.\r\nimport \"./CrossDomainEnabled.sol\";\r\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Optimism.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n uint32 public immutable l2GasLimit = 2_000_000;\r\n\r\n WETH9 public immutable l1Weth;\r\n\r\n IL1StandardBridge public immutable l1StandardBridge;\r\n\r\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\r\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\r\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\r\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\r\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\r\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\r\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\r\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _l1Weth WETH address on L1.\r\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\r\n * @param _l1StandardBridge Standard bridge contract.\r\n */\r\n constructor(\r\n WETH9 _l1Weth,\r\n address _crossDomainMessenger,\r\n IL1StandardBridge _l1StandardBridge\r\n ) CrossDomainEnabled(_crossDomainMessenger) {\r\n l1Weth = _l1Weth;\r\n l1StandardBridge = _l1StandardBridge;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Optimism.\r\n * @param target Contract on Optimism that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Optimism.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\r\n } else {\r\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\r\n\r\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\r\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\r\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\r\n\r\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\r\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\nimport \"../interfaces/WETH9.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\ninterface IRootChainManager {\r\n function depositEtherFor(address user) external payable;\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external;\r\n}\r\n\r\ninterface IFxStateSender {\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\r\n}\r\n\r\ninterface DepositManager {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount\r\n ) external;\r\n}\r\n\r\n/**\r\n * @notice Sends cross chain messages Polygon L2 network.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Polygon_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n IRootChainManager public immutable rootChainManager;\r\n IFxStateSender public immutable fxStateSender;\r\n DepositManager public immutable depositManager;\r\n address public immutable erc20Predicate;\r\n address public immutable l1Matic;\r\n WETH9 public immutable l1Weth;\r\n\r\n /**\r\n * @notice Constructs new Adapter.\r\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\r\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\r\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\r\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\r\n * @param _l1Matic matic address on l1.\r\n * @param _l1Weth WETH address on L1.\r\n */\r\n constructor(\r\n IRootChainManager _rootChainManager,\r\n IFxStateSender _fxStateSender,\r\n DepositManager _depositManager,\r\n address _erc20Predicate,\r\n address _l1Matic,\r\n WETH9 _l1Weth\r\n ) {\r\n rootChainManager = _rootChainManager;\r\n fxStateSender = _fxStateSender;\r\n depositManager = _depositManager;\r\n erc20Predicate = _erc20Predicate;\r\n l1Matic = _l1Matic;\r\n l1Weth = _l1Weth;\r\n }\r\n\r\n /**\r\n * @notice Send cross-chain message to target on Polygon.\r\n * @param target Contract on Polygon that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n fxStateSender.sendMessageToChild(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Bridge tokens to Polygon.\r\n * @param l1Token L1 token to deposit.\r\n * @param l2Token L2 token to receive.\r\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\r\n * @param to Bridge recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token,\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\r\n if (l1Token == address(l1Weth)) {\r\n l1Weth.withdraw(amount);\r\n rootChainManager.depositEtherFor{ value: amount }(to);\r\n } else if (l1Token == l1Matic) {\r\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\r\n depositManager.depositERC20ForUser(l1Token, to, amount);\r\n } else {\r\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\r\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\r\n }\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../interfaces/AdapterInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\n\r\n/**\r\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\r\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\r\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\r\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\r\n * and the Ethereum_SpokePool.\r\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\r\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\r\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\r\n * that call this contract's logic guard against reentrancy.\r\n */\r\n\r\n// solhint-disable-next-line contract-name-camelcase\r\ncontract Ethereum_Adapter is AdapterInterface {\r\n using SafeERC20 for IERC20;\r\n\r\n /**\r\n * @notice Send message to target on Ethereum.\r\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\r\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\r\n * send messages via this pass-through contract.\r\n * @param target Contract that will receive message.\r\n * @param message Data to send to target.\r\n */\r\n function relayMessage(address target, bytes calldata message) external payable override {\r\n _executeCall(target, message);\r\n emit MessageRelayed(target, message);\r\n }\r\n\r\n /**\r\n * @notice Send tokens to target.\r\n * @param l1Token L1 token to send.\r\n * @param l2Token Unused parameter in this contract.\r\n * @param amount Amount of L1 tokens to send.\r\n * @param to recipient.\r\n */\r\n function relayTokens(\r\n address l1Token,\r\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\r\n // on this network.\r\n uint256 amount,\r\n address to\r\n ) external payable override {\r\n IERC20(l1Token).safeTransfer(to, amount);\r\n emit TokensRelayed(l1Token, l2Token, amount, to);\r\n }\r\n\r\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\r\n function _executeCall(address to, bytes memory data) private {\r\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\r\n\r\n bool success;\r\n\r\n // solhint-disable-next-line no-inline-assembly\r\n assembly {\r\n let inputData := add(data, 0x20)\r\n let inputDataSize := mload(data)\r\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\r\n // value cross-chain.\r\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\r\n }\r\n require(success, \"execute call failed\");\r\n }\r\n}\r\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract RootChainManagerMock {\r\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\r\n\r\n function depositFor(\r\n address user,\r\n address rootToken,\r\n bytes calldata depositData\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract FxStateSenderMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\r\n}\r\n\r\ncontract DepositManagerMock {\r\n function depositERC20ForUser(\r\n address token,\r\n address user,\r\n uint256 amount // solhint-disable-next-line no-empty-blocks\r\n ) external {} // solhint-disable-line no-empty-blocks\r\n}\r\n\r\ncontract PolygonRegistryMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function erc20Predicate() external returns (address predicate) {}\r\n}\r\n\r\ncontract PolygonERC20PredicateMock {\r\n // solhint-disable-next-line no-empty-blocks\r\n function startExitWithBurntTokens(bytes calldata data) external {}\r\n}\r\n\r\ncontract PolygonERC20Mock is ERC20 {\r\n // solhint-disable-next-line no-empty-blocks\r\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\r\n\r\n // solhint-disable-next-line no-empty-blocks\r\n function withdraw(uint256 amount) external {}\r\n}\r\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,22 +155,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json b/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json index fcfa4176..8a801880 100644 --- a/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json +++ b/deployments/polygon/solcInputs/ea9229ed188f1300c4a413d030dbf1b6.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/erc1155/MintableERC1155.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\n\n/**\n * @title MintableERC1155\n * @notice Ownable contract enabling owner to airdrop many recipients the same token ID at once\n */\ncontract MintableERC1155 is ERC1155, Ownable {\n // Maps `tokenId` to metadata URI `tokenURI`\n mapping(uint256 => string) public _tokenURIs;\n\n event Airdrop(address caller, uint256 tokenId, address[] recipients, uint256 amount);\n\n // We are passing an empty string as the `baseURI` because we use `_tokenURIs` instead\n // to allow for IPFS URIs.\n // solhint-disable-next-line\n constructor() ERC1155(\"\") {}\n\n /**\n * @notice Creates `amount` new tokens for `recipients` of token type `tokenId`.\n * @dev Call might run out of gas if `recipients` arg too long. Might need to chunk up the list.\n * @param recipients List of airdrop recipients.\n * @param tokenId Token type to airdrop.\n * @param amount Amount of token types to airdrop.\n */\n function airdrop(\n uint256 tokenId,\n address[] memory recipients,\n uint256 amount\n ) public onlyOwner {\n for (uint256 i = 0; i < recipients.length; i++) {\n _mint(recipients[i], tokenId, amount, \"\");\n }\n emit Airdrop(_msgSender(), tokenId, recipients, amount);\n }\n\n /**\n * @notice Sets the URI for token of type `tokenId` to `tokenURI`.\n * @param tokenId Token type to set `tokenURI` for.\n * @param tokenURI URI of token metadata.\n */\n function setTokenURI(uint256 tokenId, string memory tokenURI) external onlyOwner {\n require(bytes(_tokenURIs[tokenId]).length == 0, \"uri already set\");\n\n _tokenURIs[tokenId] = tokenURI;\n emit URI(tokenURI, tokenId);\n }\n\n /**\n * @notice Returns metadata URI of token type `tokenId`.\n * @dev Instead of returning the same URI for *all* token types, we return the uri set by\n * `setTokenURI` to allow IPFS URIs for all token types.\n * @param tokenId Token type to retrieve metadata URI for.\n */\n function uri(uint256 tokenId) public view override returns (string memory) {\n return _tokenURIs[tokenId];\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" diff --git a/deployments/rinkeby/Arbitrum_Adapter.json b/deployments/rinkeby/Arbitrum_Adapter.json index 70186d2d..5d851f90 100644 --- a/deployments/rinkeby/Arbitrum_Adapter.json +++ b/deployments/rinkeby/Arbitrum_Adapter.json @@ -224,7 +224,7 @@ "args": ["0x578BAde599406A8fE3d24Fd7f7211c0911F5B29e", "0x70C143928eCfFaf9F5b406f7f4fC28Dc43d68380"], "numDeployments": 1, "solcInputHash": "fc82eeb0fff4196cd4e0dfec8a3b3aca", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xbdebabe1e5a8750542eae714d268cf9c3b18c8bfe8cacce431ddefe6bcaf4334\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"_l1ArbitrumInbox\",\"type\":\"address\"},{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"_l1ERC20GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getL1CallValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC20GatewayRouter\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1ERC20GatewayLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Inbox\",\"outputs\":[{\"internalType\":\"contract ArbitrumL1InboxLike\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2MaxSubmissionCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2RefundL2Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_l1ArbitrumInbox\":\"Inbox helper contract to send messages to Arbitrum.\",\"_l1ERC20GatewayRouter\":\"ERC20 gateway router contract to send tokens to Arbitrum.\"}},\"getL1CallValue()\":{\"returns\":{\"_0\":\"amount of ETH that this contract needs to hold in order for relayMessage to succeed.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Arbitrum that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"getL1CallValue()\":{\"notice\":\"Returns required amount of ETH to send a message via the Inbox.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Arbitrum.This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox successfully, or the message will get stuck.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Arbitrum.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Arbitrum_Adapter.sol\":\"Arbitrum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Arbitrum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface ArbitrumL1InboxLike {\\n function createRetryableTicket(\\n address destAddr,\\n uint256 arbTxCallValue,\\n uint256 maxSubmissionCost,\\n address submissionRefundAddress,\\n address valueRefundAddress,\\n uint256 maxGas,\\n uint256 gasPriceBid,\\n bytes calldata data\\n ) external payable returns (uint256);\\n}\\n\\ninterface ArbitrumL1ERC20GatewayLike {\\n function outboundTransfer(\\n address _token,\\n address _to,\\n uint256 _amount,\\n uint256 _maxGas,\\n uint256 _gasPriceBid,\\n bytes calldata _data\\n ) external payable returns (bytes memory);\\n\\n function getGateway(address _token) external view returns (address);\\n}\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Arbitrum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\\n uint32 public immutable l2GasLimit = 2_000_000;\\n\\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\\n // ticket\\u2019s calldata in the retry buffer. (current base submission fee is queryable via\\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\\n // 0x000000000000000000000000000000000000006E.\\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\\n\\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\\n\\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\\n address public immutable l2RefundL2Address;\\n\\n ArbitrumL1InboxLike public immutable l1Inbox;\\n\\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\\n */\\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\\n l1Inbox = _l1ArbitrumInbox;\\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\\n\\n l2RefundL2Address = msg.sender;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param target Contract on Arbitrum that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\\n target, // destAddr destination L2 contract address\\n 0, // l2CallValue call value for retryable L2 message\\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\\n l2GasPrice, // gasPriceBid price bid for L2 execution\\n message // data ABI encoded data of L2 message\\n );\\n\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Arbitrum.\\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\\n * successfully, or the message will get stuck.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for Arbitrum.\\n uint256 amount,\\n address to\\n ) external payable override {\\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\\n\\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\\n\\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\\n bytes memory data = abi.encode(l2MaxSubmissionCost, \\\"\\\");\\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\\n\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n /**\\n * @notice Returns required amount of ETH to send a message via the Inbox.\\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\\n */\\n function getL1CallValue() public pure returns (uint256) {\\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\\n }\\n\\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\\n requiredL1CallValue = getL1CallValue();\\n require(address(this).balance >= requiredL1CallValue, \\\"Insufficient ETH balance\\\");\\n }\\n}\\n\",\"keccak256\":\"0xbdebabe1e5a8750542eae714d268cf9c3b18c8bfe8cacce431ddefe6bcaf4334\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610140604052621e8480608052662386f26fc1000060a05264012a05f20060c05234801561002c57600080fd5b5060405161128438038061128483398101604081905261004b91610080565b6001600160a01b039182166101005216610120523360e0526100ba565b6001600160a01b038116811461007d57600080fd5b50565b6000806040838503121561009357600080fd5b825161009e81610068565b60208401519092506100af81610068565b809150509250929050565b60805160a05160c05160e051610100516101205161111a61016a6000396000818160d501528181610333015261047001526000818161014301526105cd0152600081816101ab0152818161062e015261064f0152600081816101770152818161028b015281816104c70152610691015260008181610228015281816102b5015281816103c5015261060d0152600081816101df01528181610269015281816104a50152610670015261111a6000f3fe6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212208a27fef820b6942c0cf40e5cb9184416af0fd6bd08e2b4c6a9bfebf2716b4a1264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100965760003560e01c80639ae3668511610069578063cf6e65b71161004e578063cf6e65b7146101cd578063e599477e14610216578063e6eb8ade1461024a57600080fd5b80639ae36685146101655780639c3ba2001461019957600080fd5b806308f1ed151461009b5780631ba4a9cb146100c357806352c8c75c1461011c5780638134f38514610131575b600080fd5b3480156100a757600080fd5b506100b061025d565b6040519081526020015b60405180910390f35b3480156100cf57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ba565b61012f61012a366004610c47565b6102de565b005b34801561013d57600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b34801561017157600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b3480156101a557600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d957600080fd5b506102017f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016100ba565b34801561022257600080fd5b506100b07f000000000000000000000000000000000000000000000000000000000000000081565b61012f610258366004610d5e565b6105bf565b60006102af63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000610e20565b6102d9907f0000000000000000000000000000000000000000000000000000000000000000610e5d565b905090565b60006102e8610756565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bda009fe90602401602060405180830381865afa15801561037a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039e9190610e75565b90506103c173ffffffffffffffffffffffffffffffffffffffff871682866107d4565b60007f000000000000000000000000000000000000000000000000000000000000000060405160200161040591815260406020820181905260009082015260600190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527fd2ce7d65000000000000000000000000000000000000000000000000000000008252915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063d2ce7d659085906104f1908b9089908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000908a90600401610f08565b60006040518083038185885af115801561050f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105569190810190610f65565b506040805173ffffffffffffffffffffffffffffffffffffffff898116825288811660208301528183018890528616606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050505050565b60006105c9610756565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663679b6ded828560007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008b6040518a63ffffffff1660e01b81526004016106d4989796959493929190610fdc565b60206040518083038185885af11580156106f2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610717919061104b565b507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48383604051610749929190611064565b60405180910390a1505050565b600061076061025d565b9050804710156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e6365000000000000000060448201526064015b60405180910390fd5b90565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061104b565b6108799190610e5d565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061090990859061090f565b50505050565b6000610971826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a209092919063ffffffff16565b805190915015610a1b578080602001905181019061098f9190611093565b610a1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107c8565b505050565b6060610a2f8484600085610a39565b90505b9392505050565b606082471015610acb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107c8565b73ffffffffffffffffffffffffffffffffffffffff85163b610b49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107c8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b7291906110b5565b60006040518083038185875af1925050503d8060008114610baf576040519150601f19603f3d011682016040523d82523d6000602084013e610bb4565b606091505b5091509150610bc4828286610bcf565b979650505050505050565b60608315610bde575081610a32565b825115610bee5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c891906110d1565b73ffffffffffffffffffffffffffffffffffffffff81168114610c4457600080fd5b50565b60008060008060808587031215610c5d57600080fd5b8435610c6881610c22565b93506020850135610c7881610c22565b9250604085013591506060850135610c8f81610c22565b939692955090935050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1057610d10610c9a565b604052919050565b600067ffffffffffffffff821115610d3257610d32610c9a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215610d7157600080fd5b8235610d7c81610c22565b9150602083013567ffffffffffffffff811115610d9857600080fd5b8301601f81018513610da957600080fd5b8035610dbc610db782610d18565b610cc9565b818152866020838501011115610dd157600080fd5b816020840160208301376000602083830101528093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e5857610e58610df1565b500290565b60008219821115610e7057610e70610df1565b500190565b600060208284031215610e8757600080fd5b8151610a3281610c22565b60005b83811015610ead578181015183820152602001610e95565b838111156109095750506000910152565b60008151808452610ed6816020860160208601610e92565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015263ffffffff8516606083015283608083015260c060a0830152610f5960c0830184610ebe565b98975050505050505050565b600060208284031215610f7757600080fd5b815167ffffffffffffffff811115610f8e57600080fd5b8201601f81018413610f9f57600080fd5b8051610fad610db782610d18565b818152856020838501011115610fc257600080fd5b610fd3826020830160208601610e92565b95945050505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c1684528a6020850152896040850152808916606085015280881660808501525063ffffffff861660a08401528460c08401528060e084015261103c81840185610ebe565b9b9a5050505050505050505050565b60006020828403121561105d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a2f6040830184610ebe565b6000602082840312156110a557600080fd5b81518015158114610a3257600080fd5b600082516110c7818460208701610e92565b9190910192915050565b602081526000610a326020830184610ebe56fea26469706673582212208a27fef820b6942c0cf40e5cb9184416af0fd6bd08e2b4c6a9bfebf2716b4a1264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Ethereum_Adapter.json b/deployments/rinkeby/Ethereum_Adapter.json index 31da045e..1c3eab16 100644 --- a/deployments/rinkeby/Ethereum_Adapter.json +++ b/deployments/rinkeby/Ethereum_Adapter.json @@ -117,7 +117,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n // solhint-disable-next-line no-inline-assembly\\n\\n bool success;\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd553b891966b6d01d77af8eccc394b7554c3fce1275e6470feecb72cbe173ae4\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to send.\",\"l1Token\":\"L1 token to send.\",\"l2Token\":\"Unused parameter in this contract.\",\"to\":\"recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"relayMessage(address,bytes)\":{\"notice\":\"Send message to target on Ethereum.This function, and contract overall, is not useful in practice except that the HubPool expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must send messages via this pass-through contract.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Send tokens to target.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Ethereum SpokePool.This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool and the Ethereum_SpokePool.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Ethereum_Adapter.sol\":\"Ethereum_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Ethereum_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\\n * contract between HubPool and SpokePool on the same chain. Its named \\\"Ethereum_Adapter\\\" because a core assumption\\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\\n * and the Ethereum_SpokePool.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Ethereum_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Send message to target on Ethereum.\\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\\n * send messages via this pass-through contract.\\n * @param target Contract that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n _executeCall(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Send tokens to target.\\n * @param l1Token L1 token to send.\\n * @param l2Token Unused parameter in this contract.\\n * @param amount Amount of L1 tokens to send.\\n * @param to recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\\n // on this network.\\n uint256 amount,\\n address to\\n ) external payable override {\\n IERC20(l1Token).safeTransfer(to, amount);\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n\\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\\n function _executeCall(address to, bytes memory data) private {\\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \\\"value\\\" field.\\n // solhint-disable-next-line no-inline-assembly\\n\\n bool success;\\n assembly {\\n let inputData := add(data, 0x20)\\n let inputDataSize := mload(data)\\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\\n // value cross-chain.\\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\\n }\\n require(success, \\\"execute call failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd553b891966b6d01d77af8eccc394b7554c3fce1275e6470feecb72cbe173ae4\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506107fa806100206000396000f3fe6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c36600461056e565b610056565b005b6100416100513660046105ea565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff85168284610123565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6100e682826101b5565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610117929190610744565b60405180910390a15050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101b0908490610237565b505050565b600060208201825160008082846000895af192505050806101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b6000610299826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103439092919063ffffffff16565b8051909150156101b057808060200190518101906102b79190610773565b6101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161022e565b6060610352848460008561035c565b90505b9392505050565b6060824710156103ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161022e565b73ffffffffffffffffffffffffffffffffffffffff85163b61046c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161022e565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104959190610795565b60006040518083038185875af1925050503d80600081146104d2576040519150601f19603f3d011682016040523d82523d6000602084013e6104d7565b606091505b50915091506104e78282866104f2565b979650505050505050565b60608315610501575081610355565b8251156105115782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161022e91906107b1565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056957600080fd5b919050565b6000806000806080858703121561058457600080fd5b61058d85610545565b935061059b60208601610545565b9250604085013591506105b060608601610545565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156105fd57600080fd5b61060683610545565b9150602083013567ffffffffffffffff8082111561062357600080fd5b818501915085601f83011261063757600080fd5b813581811115610649576106496105bb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561068f5761068f6105bb565b816040528281528860208487010111156106a857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156106e55781810151838201526020016106cd565b838111156106f4576000848401525b50505050565b600081518084526107128160208601602086016106ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061035260408301846106fa565b60006020828403121561078557600080fd5b8151801515811461035557600080fd5b600082516107a78184602087016106ca565b9190910192915050565b60208152600061035560208301846106fa56fea2646970667358221220c375741f9f8699c2539c58570c2a4ba4c1e9099e507ad943cb7b7cfe570455d264736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100295760003560e01c806352c8c75c1461002e578063e6eb8ade14610043575b600080fd5b61004161003c36600461056e565b610056565b005b6100416100513660046105ea565b6100dc565b61007773ffffffffffffffffffffffffffffffffffffffff85168284610123565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6100e682826101b5565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610117929190610744565b60405180910390a15050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526101b0908490610237565b505050565b600060208201825160008082846000895af192505050806101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f657865637574652063616c6c206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b6000610299826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103439092919063ffffffff16565b8051909150156101b057808060200190518101906102b79190610773565b6101b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161022e565b6060610352848460008561035c565b90505b9392505050565b6060824710156103ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161022e565b73ffffffffffffffffffffffffffffffffffffffff85163b61046c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161022e565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104959190610795565b60006040518083038185875af1925050503d80600081146104d2576040519150601f19603f3d011682016040523d82523d6000602084013e6104d7565b606091505b50915091506104e78282866104f2565b979650505050505050565b60608315610501575081610355565b8251156105115782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161022e91906107b1565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056957600080fd5b919050565b6000806000806080858703121561058457600080fd5b61058d85610545565b935061059b60208601610545565b9250604085013591506105b060608601610545565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156105fd57600080fd5b61060683610545565b9150602083013567ffffffffffffffff8082111561062357600080fd5b818501915085601f83011261063757600080fd5b813581811115610649576106496105bb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561068f5761068f6105bb565b816040528281528860208487010111156106a857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156106e55781810151838201526020016106cd565b838111156106f4576000848401525b50505050565b600081518084526107128160208601602086016106ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061035260408301846106fa565b60006020828403121561078557600080fd5b8151801515811461035557600080fd5b600082516107a78184602087016106ca565b9190910192915050565b60208152600061035560208301846106fa56fea2646970667358221220c375741f9f8699c2539c58570c2a4ba4c1e9099e507ad943cb7b7cfe570455d264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Ethereum_SpokePool.json b/deployments/rinkeby/Ethereum_SpokePool.json index d1e8f2d5..a2a6f04a 100644 --- a/deployments/rinkeby/Ethereum_SpokePool.json +++ b/deployments/rinkeby/Ethereum_SpokePool.json @@ -1127,7 +1127,7 @@ ], "numDeployments": 2, "solcInputHash": "1bf8793c065ccb196e5a60f53c731ca8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n bytes32 indexed relayHash,\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\\r\\n for (uint32 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint32).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 relayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayHash,\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0xeb7a64b4ec0592d18254c802d35779fc6aabfca5c6817c52b4344a3946e5654e\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xbd436408b1294166c3459d9f23f80358ae99e95b95b474a99525949e3bf8569d\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_hubPool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"timerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"EmergencyDeleteRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"EnabledDepositRoute\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ExecutedRelayerRefundRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalFilledAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fillAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSlowRelay\",\"type\":\"bool\"}],\"name\":\"FilledRelay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"FundsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"RelayedRootBundle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"RequestedSpeedUpDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"newBuffer\",\"type\":\"uint32\"}],\"name\":\"SetDepositQuoteTimeBuffer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"SetHubPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"SetXDomainAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"TokensBridged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"crossDomainAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositQuoteTimeBuffer\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rootBundleId\",\"type\":\"uint256\"}],\"name\":\"emergencyDeleteRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"enabledDepositRoutes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountToReturn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"refundAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"leafId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"l2TokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"refundAddresses\",\"type\":\"address[]\"}],\"internalType\":\"struct SpokePoolInterface.RelayerRefundLeaf\",\"name\":\"relayerRefundLeaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeRelayerRefundLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"rootBundleId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"name\":\"executeSlowRelayLeaf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"}],\"name\":\"fillRelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destinationToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxTokensToSend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"repaymentChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originChainId\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"realizedLpFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"relayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"fillRelayWithUpdatedFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hubPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"numberOfDeposits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"relayFills\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"}],\"name\":\"relayRootBundle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rootBundles\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"slowRelayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"relayerRefundRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCrossDomainAdmin\",\"type\":\"address\"}],\"name\":\"setCrossDomainAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setCurrentTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"newDepositQuoteTimeBuffer\",\"type\":\"uint32\"}],\"name\":\"setDepositQuoteTimeBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setEnableRoute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newHubPool\",\"type\":\"address\"}],\"name\":\"setHubPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"newRelayerFeePct\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"depositId\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"depositorSignature\",\"type\":\"bytes\"}],\"name\":\"speedUpDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedNativeToken\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"chainId()\":{\"details\":\"Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\"},\"constructor\":{\"params\":{\"_hubPool\":\"Hub pool address to set. Can be changed by admin.\",\"_wethAddress\":\"Weth address for this network to set.\",\"timerAddress\":\"Timer address to set.\"}},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\"}},\"emergencyDeleteRootBundle(uint256)\":{\"params\":{\"rootBundleId\":\"Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256 to ensure that a small input range doesn't limit which indices this method is able to reach.\"}},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"params\":{\"proof\":\"Inclusion proof for this leaf in relayer refund root in root bundle.\",\"relayerRefundLeaf\":\"Contains all data necessary to reconstruct leaf contained in root bundle and to refund relayer. This data structure is explained in detail in the SpokePoolInterface.\",\"rootBundleId\":\"Unique ID of root bundle containing relayer refund root that this leaf is contained in.\"}},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"details\":\"This function assumes that the relay's destination chain ID is the current chain ID, which prevents the caller from executing a slow relay intended for another chain on this chain.\",\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"proof\":\"Inclusion proof for this leaf in slow relay root in root bundle.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"rootBundleId\":\"Unique ID of root bundle containing slow relay root that this leaf is contained in.\"}},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Fee % to keep as relayer, specified by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"params\":{\"amount\":\"Full size of the deposit.\",\"depositId\":\"Unique deposit ID on origin spoke pool.\",\"depositor\":\"Depositor on origin chain who set this chain as the destination chain.\",\"depositorSignature\":\"Depositor-signed message containing updated fee %.\",\"destinationToken\":\"Token to send to recipient. Should be mapped to the origin token, origin chain ID and this chain ID via a mapping on the HubPool.\",\"maxTokensToSend\":\"Max amount of tokens to send recipient. If higher than amount, then caller will send recipient the full relay amount.\",\"newRelayerFeePct\":\"New fee % to keep as relayer also specified by depositor.\",\"originChainId\":\"Chain of SpokePool where deposit originated.\",\"realizedLpFeePct\":\"Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on quote time.\",\"recipient\":\"Specified recipient on this chain.\",\"relayerFeePct\":\"Original fee % to keep as relayer set by depositor.\",\"repaymentChainId\":\"Chain of SpokePool where relayer wants to be refunded after the challenge window has passed.\"}},\"getCurrentTime()\":{\"returns\":{\"_0\":\"uint for the current Testable timestamp.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"relayRootBundle(bytes32,bytes32)\":{\"params\":{\"relayerRefundRoot\":\"Merkle root containing relayer refund leaves that can be individually executed via executeRelayerRefundLeaf().\",\"slowRelayRoot\":\"Merkle root containing slow relay fulfillment leaves that can be individually executed via executeSlowRelayLeaf().\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setCrossDomainAdmin(address)\":{\"params\":{\"newCrossDomainAdmin\":\"New cross domain admin.\"}},\"setCurrentTime(uint256)\":{\"details\":\"Will revert if not running in test mode.\",\"params\":{\"time\":\"timestamp to set current Testable time to.\"}},\"setDepositQuoteTimeBuffer(uint32)\":{\"params\":{\"newDepositQuoteTimeBuffer\":\"New quote time buffer.\"}},\"setEnableRoute(address,uint256,bool)\":{\"params\":{\"destinationChainId\":\"Chain ID for where depositor wants to receive funds.\",\"enabled\":\"True to enable deposits, False otherwise.\",\"originToken\":\"Token that depositor can deposit to this contract.\"}},\"setHubPool(address)\":{\"params\":{\"newHubPool\":\"New hub pool.\"}},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"params\":{\"depositId\":\"Deposit to update fee for that originated in this contract.\",\"depositor\":\"Signer of the update fee message who originally submitted the deposit. If the deposit doesn't exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor did in fact submit a relay.\",\"depositorSignature\":\"Signed message containing the depositor address, this contract chain ID, the updated relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\",\"newRelayerFeePct\":\"New relayer fee that relayers can use.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainId()\":{\"notice\":\"Returns chain ID for this network.\"},\"constructor\":{\"notice\":\"Construct the Ethereum SpokePool.\"},\"deposit(address,address,uint256,uint256,uint64,uint32)\":{\"notice\":\"Called by user to bridge funds from origin to destination chain. Depositor will effectively lock tokens in this contract and receive a destination token on the destination chain. The origin => destination token mapping is stored on the L1 HubPool.The caller must first approve this contract to spend amount of originToken.The originToken => destinationChainId must be enabled.This method is payable because the caller is able to deposit native token if the originToken is wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\"},\"emergencyDeleteRootBundle(uint256)\":{\"notice\":\"This method is intended to only be used in emergencies where a bad root bundle has reached the SpokePool.\"},\"executeRelayerRefundLeaf(uint32,(uint256,uint256,uint256[],uint32,address,address[]),bytes32[])\":{\"notice\":\"Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they sent to the recipient plus a relayer fee.\"},\"executeSlowRelayLeaf(address,address,address,uint256,uint256,uint64,uint64,uint32,uint32,bytes32[])\":{\"notice\":\"Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the relay to the recipient, less fees.\"},\"fillRelay(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint32)\":{\"notice\":\"Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient. Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid. If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid, then relayer will not receive any refund.All of the deposit data can be found via on-chain events from the origin SpokePool, except for the realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee % is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm as described in a UMIP linked to the HubPool's identifier.\"},\"fillRelayWithUpdatedFee(address,address,address,uint256,uint256,uint256,uint256,uint64,uint64,uint64,uint32,bytes)\":{\"notice\":\"Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\"},\"getCurrentTime()\":{\"notice\":\"Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. Otherwise, it will return the block timestamp.\"},\"relayRootBundle(bytes32,bytes32)\":{\"notice\":\"This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\"},\"setCrossDomainAdmin(address)\":{\"notice\":\"Change cross domain admin address. Callable by admin only.\"},\"setCurrentTime(uint256)\":{\"notice\":\"Sets the current time.\"},\"setDepositQuoteTimeBuffer(uint32)\":{\"notice\":\"Change allowance for deposit quote time to differ from current block time. Callable by admin only.\"},\"setEnableRoute(address,uint256,bool)\":{\"notice\":\"Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\"},\"setHubPool(address)\":{\"notice\":\"Change L1 hub pool address. Callable by admin only.\"},\"speedUpDeposit(address,uint64,uint32,bytes)\":{\"notice\":\"Convenience method that depositor can use to signal to relayer to use updated fee.Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they risk their fills getting disputed for being invalid, for example if the depositor never actually signed the update fee message.This function will revert if the depositor did not sign a message containing the updated fee for the deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\"}},\"notice\":\"Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Ethereum_SpokePool.sol\":\"Ethereum_SpokePool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n}\\n\",\"keccak256\":\"0x32c202bd28995dd20c4347b7c6467a6d3241c74c8ad3edcbb610cd9205916c45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n // Check the signature length\\n // - case 65: r,s,v signature (standard)\\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else if (signature.length == 64) {\\n bytes32 r;\\n bytes32 vs;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n assembly {\\n r := mload(add(signature, 0x20))\\n vs := mload(add(signature, 0x40))\\n }\\n return tryRecover(hash, r, vs);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0x3c07f43e60e099b3b157243b3152722e73b80eeb7985c2cd73712828d7f7da29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev These functions deal with verification of Merkle Trees proofs.\\n *\\n * The proofs can be generated using the JavaScript library\\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\\n *\\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\\n */\\nlibrary MerkleProof {\\n /**\\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\\n * defined by `root`. For this, a `proof` must be provided, containing\\n * sibling hashes on the branch from the leaf to the root of the tree. Each\\n * pair of leaves and each pair of pre-images are assumed to be sorted.\\n */\\n function verify(\\n bytes32[] memory proof,\\n bytes32 root,\\n bytes32 leaf\\n ) internal pure returns (bool) {\\n return processProof(proof, leaf) == root;\\n }\\n\\n /**\\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\\n * hash matches the root of the tree. When processing the proof, the pairs\\n * of leafs & pre-images are assumed to be sorted.\\n *\\n * _Available since v4.4._\\n */\\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\\n bytes32 computedHash = leaf;\\n for (uint256 i = 0; i < proof.length; i++) {\\n bytes32 proofElement = proof[i];\\n if (computedHash <= proofElement) {\\n // Hash(current computed hash + current element of the proof)\\n computedHash = _efficientHash(computedHash, proofElement);\\n } else {\\n // Hash(current element of the proof + current computed hash)\\n computedHash = _efficientHash(proofElement, computedHash);\\n }\\n }\\n return computedHash;\\n }\\n\\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\\n assembly {\\n mstore(0x00, a)\\n mstore(0x20, b)\\n value := keccak256(0x00, 0x40)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xea64fbaccbf9d8c235cf6838240ddcebb97f9fc383660289e9dff32e4fb85f7a\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"@uma/core/contracts/common/implementation/Testable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Timer.sol\\\";\\n\\n/**\\n * @title Base class that provides time overrides, but only if being run in test mode.\\n */\\nabstract contract Testable {\\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\\n // Note: this variable should be set on construction and never modified.\\n address public timerAddress;\\n\\n /**\\n * @notice Constructs the Testable contract. Called by child contracts.\\n * @param _timerAddress Contract that stores the current time in a testing environment.\\n * Must be set to 0x0 for production environments that use live time.\\n */\\n constructor(address _timerAddress) {\\n timerAddress = _timerAddress;\\n }\\n\\n /**\\n * @notice Reverts if not running in test mode.\\n */\\n modifier onlyIfTest {\\n require(timerAddress != address(0x0));\\n _;\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set current Testable time to.\\n */\\n function setCurrentTime(uint256 time) external onlyIfTest {\\n Timer(timerAddress).setCurrentTime(time);\\n }\\n\\n /**\\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\\n * Otherwise, it will return the block timestamp.\\n * @return uint for the current Testable timestamp.\\n */\\n function getCurrentTime() public view virtual returns (uint256) {\\n if (timerAddress != address(0x0)) {\\n return Timer(timerAddress).getCurrentTime();\\n } else {\\n return block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0254b45747293bb800373a58d123969adec0428f7be79dc941cab10fcad09918\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/Timer.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Universal store of current contract time for testing environments.\\n */\\ncontract Timer {\\n uint256 private currentTime;\\n\\n constructor() {\\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\\n }\\n\\n /**\\n * @notice Sets the current time.\\n * @dev Will revert if not running in test mode.\\n * @param time timestamp to set `currentTime` to.\\n */\\n function setCurrentTime(uint256 time) external {\\n currentTime = time;\\n }\\n\\n /**\\n * @notice Gets the currentTime variable set in the Timer.\\n * @return uint256 for the current Testable timestamp.\\n */\\n function getCurrentTime() public view returns (uint256) {\\n return currentTime;\\n }\\n}\\n\",\"keccak256\":\"0x9e0dd7389718bd5d1da910273a6f4cee98ee22bfc0c92bde0f0955c0e23adb5e\",\"license\":\"AGPL-3.0-only\"},\"contracts/Ethereum_SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePool.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\\n */\\ncontract Ethereum_SpokePool is SpokePool, Ownable {\\n /**\\n * @notice Construct the Ethereum SpokePool.\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\n * @param _wethAddress Weth address for this network to set.\\n * @param timerAddress Timer address to set.\\n */\\n constructor(\\n address _hubPool,\\n address _wethAddress,\\n address timerAddress\\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\\n\\n /**************************************\\n * INTERNAL FUNCTIONS *\\n **************************************/\\n\\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\\n }\\n\\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\\n function _requireAdminSender() internal override onlyOwner {}\\n}\\n\",\"keccak256\":\"0xe4bc6410665d75f98cb23420cfd30dc88091204810e0af7847e65debbf8edeea\",\"license\":\"GPL-3.0-only\"},\"contracts/HubPoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/AdapterInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @notice Concise list of functions in HubPool implementation.\\n */\\ninterface HubPoolInterface {\\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\\n struct PoolRebalanceLeaf {\\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\\n uint256 chainId;\\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\\n uint256[] bundleLpFees;\\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\\n int256[] netSendAmounts;\\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\\n int256[] runningBalances;\\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\\n // leaf for a specific chainId should have a groupIndex equal to 0.\\n uint256 groupIndex;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint8 leafId;\\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\\n // relays on this chain in this bundle in the order of whitelisting.\\n address[] l1Tokens;\\n }\\n\\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\\n // that can be executed later to:\\n // - Send funds from this contract to a SpokePool or vice versa\\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \\\"slow\\\" relay\\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\\n struct RootBundle {\\n // Contains leaves instructing this contract to send funds to SpokePools.\\n bytes32 poolRebalanceRoot;\\n // Relayer refund merkle root to be published to a SpokePool.\\n bytes32 relayerRefundRoot;\\n // Slow relay merkle root to be published to a SpokePool.\\n bytes32 slowRelayRoot;\\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\\n uint256 claimedBitMap;\\n // Proposer of this root bundle.\\n address proposer;\\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\\n // of leaves are executed, a new root bundle can be proposed\\n uint8 unclaimedPoolRebalanceLeafCount;\\n // When root bundle challenge period passes and this root bundle becomes executable.\\n uint32 challengePeriodEndTimestamp;\\n }\\n\\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\\n // cumulative LP positions and if this token is enabled for deposits.\\n struct PooledToken {\\n // LP token given to LPs of a specific L1 token.\\n address lpToken;\\n // True if accepting new LP's.\\n bool isEnabled;\\n // Timestamp of last LP fee update.\\n uint32 lastLpFeeUpdate;\\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\\n // back later.\\n int256 utilizedReserves;\\n // Number of LP funds held in contract less utilized reserves.\\n uint256 liquidReserves;\\n // Number of LP funds reserved to pay out to LPs as fees.\\n uint256 undistributedLpFees;\\n }\\n\\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\\n struct CrossChainContract {\\n address adapter;\\n address spokePool;\\n }\\n\\n function setPaused(bool pause) external;\\n\\n function emergencyDeleteProposal() external;\\n\\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\\n\\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\\n\\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\\n\\n function setLiveness(uint32 newLiveness) external;\\n\\n function setIdentifier(bytes32 newIdentifier) external;\\n\\n function setCrossChainContracts(\\n uint256 l2ChainId,\\n address adapter,\\n address spokePool\\n ) external;\\n\\n function enableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function disableL1TokenForLiquidityProvision(address l1Token) external;\\n\\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\\n\\n function removeLiquidity(\\n address l1Token,\\n uint256 lpTokenAmount,\\n bool sendEth\\n ) external;\\n\\n function exchangeRateCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\\n\\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\\n\\n function sync(address l1Token) external;\\n\\n function proposeRootBundle(\\n uint256[] memory bundleEvaluationBlockNumbers,\\n uint8 poolRebalanceLeafCount,\\n bytes32 poolRebalanceRoot,\\n bytes32 relayerRefundRoot,\\n bytes32 slowRelayRoot\\n ) external;\\n\\n function executeRootBundle(\\n uint256 chainId,\\n uint256 groupIndex,\\n uint256[] memory bundleLpFees,\\n int256[] memory netSendAmounts,\\n int256[] memory runningBalances,\\n uint8 leafId,\\n address[] memory l1Tokens,\\n bytes32[] memory proof\\n ) external;\\n\\n function disputeRootBundle() external;\\n\\n function claimProtocolFeesCaptured(address l1Token) external;\\n\\n function setPoolRebalanceRoute(\\n uint256 destinationChainId,\\n address l1Token,\\n address destinationToken\\n ) external;\\n\\n function setDepositRoute(\\n uint256 originChainId,\\n uint256 destinationChainId,\\n address originToken,\\n bool depositsEnabled\\n ) external;\\n\\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\\n external\\n view\\n returns (address destinationToken);\\n\\n function loadEthForL2Calls() external payable;\\n}\\n\",\"keccak256\":\"0xbe0b8e72199362e11c0570a1023e5446c81f97ea429d40950f667541df1acdd9\",\"license\":\"GPL-3.0-only\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/MerkleLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./SpokePoolInterface.sol\\\";\\nimport \\\"./HubPoolInterface.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\\\";\\n\\n/**\\n * @notice Library to help with merkle roots, proofs, and claims.\\n */\\nlibrary MerkleLib {\\n /**\\n * @notice Verifies that a repayment is contained within a merkle root.\\n * @param root the merkle root.\\n * @param rebalance the rebalance struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\\n */\\n function verifyPoolRebalance(\\n bytes32 root,\\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\\n }\\n\\n /**\\n * @notice Verifies that a relayer refund is contained within a merkle root.\\n * @param root the merkle root.\\n * @param refund the refund struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\\n */\\n function verifyRelayerRefund(\\n bytes32 root,\\n SpokePoolInterface.RelayerRefundLeaf memory refund,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\\n }\\n\\n /**\\n * @notice Verifies that a distribution is contained within a merkle root.\\n * @param root the merkle root.\\n * @param slowRelayFulfillment the relayData fulfillment struct.\\n * @param proof the merkle proof.\\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\\n */\\n function verifySlowRelayFulfillment(\\n bytes32 root,\\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\\n bytes32[] memory proof\\n ) internal pure returns (bool) {\\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\\n }\\n\\n // The following functions are primarily copied from\\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\\n\\n /**\\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to check in the bitmap.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\\n uint256 mask = (1 << claimedBitIndex);\\n return claimedWord & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\\n * @param index the index to mark in the bitmap.\\n */\\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\\n uint256 claimedWordIndex = index / 256;\\n uint256 claimedBitIndex = index % 256;\\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\\n }\\n\\n /**\\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\\n */\\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\\n uint256 mask = (1 << index);\\n return claimedBitMap & mask == mask;\\n }\\n\\n /**\\n * @notice Marks an index in a claimedBitMap as claimed.\\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\\n * can't be > 255.\\n * @param index the index to mark in the bitmap.\\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\\n */\\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\\n return claimedBitMap | (1 << index % 256);\\n }\\n}\\n\",\"keccak256\":\"0x5b49211d8b8e5a2792d08adb818fddc2ad8abaef45822f91ca678ceb7ea018ea\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport \\\"./MerkleLib.sol\\\";\\r\\nimport \\\"./interfaces/WETH9.sol\\\";\\r\\nimport \\\"./Lockable.sol\\\";\\r\\nimport \\\"./SpokePoolInterface.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\r\\n\\r\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/Testable.sol\\\";\\r\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title SpokePool\\r\\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\\r\\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\\r\\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\\r\\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\\r\\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \\\"data worker\\\",\\r\\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\\r\\n */\\r\\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\\r\\n using SafeERC20 for IERC20;\\r\\n using Address for address;\\r\\n\\r\\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\\r\\n // then this address should be set to the same owner as the HubPool and the whole system.\\r\\n address public crossDomainAdmin;\\r\\n\\r\\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\\r\\n // refunds and slow relays.\\r\\n address public hubPool;\\r\\n\\r\\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\\r\\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\\r\\n WETH9 public immutable wrappedNativeToken;\\r\\n\\r\\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\\r\\n // caller to use an approximately \\\"current\\\" realized fee. Defaults to 10 minutes.\\r\\n uint32 public depositQuoteTimeBuffer = 600;\\r\\n\\r\\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\\r\\n uint32 public numberOfDeposits;\\r\\n\\r\\n // This contract can store as many root bundles as the HubPool chooses to publish here.\\r\\n RootBundle[] public rootBundles;\\r\\n\\r\\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\\r\\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\\r\\n\\r\\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\\r\\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\\r\\n // relay, the fees, and the agents are all parameters included in the hash key.\\r\\n mapping(bytes32 => uint256) public relayFills;\\r\\n\\r\\n /****************************************\\r\\n * EVENTS *\\r\\n ****************************************/\\r\\n event SetXDomainAdmin(address indexed newAdmin);\\r\\n event SetHubPool(address indexed newHubPool);\\r\\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\\r\\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\\r\\n event FundsDeposited(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address indexed originToken,\\r\\n address recipient,\\r\\n address indexed depositor\\r\\n );\\r\\n event RequestedSpeedUpDeposit(\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 indexed depositId,\\r\\n address indexed depositor,\\r\\n bytes depositorSignature\\r\\n );\\r\\n event FilledRelay(\\r\\n bytes32 indexed relayHash,\\r\\n uint256 amount,\\r\\n uint256 totalFilledAmount,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint64 realizedLpFeePct,\\r\\n uint32 depositId,\\r\\n address destinationToken,\\r\\n address indexed relayer,\\r\\n address indexed depositor,\\r\\n address recipient,\\r\\n bool isSlowRelay\\r\\n );\\r\\n event RelayedRootBundle(\\r\\n uint32 indexed rootBundleId,\\r\\n bytes32 indexed relayerRefundRoot,\\r\\n bytes32 indexed slowRelayRoot\\r\\n );\\r\\n event ExecutedRelayerRefundRoot(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint256[] refundAmounts,\\r\\n uint32 indexed rootBundleId,\\r\\n uint32 indexed leafId,\\r\\n address l2TokenAddress,\\r\\n address[] refundAddresses,\\r\\n address caller\\r\\n );\\r\\n event TokensBridged(\\r\\n uint256 amountToReturn,\\r\\n uint256 indexed chainId,\\r\\n uint32 indexed leafId,\\r\\n address indexed l2TokenAddress,\\r\\n address caller\\r\\n );\\r\\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\\r\\n\\r\\n /**\\r\\n * @notice Construct the base SpokePool.\\r\\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\\r\\n * @param _hubPool Hub pool address to set. Can be changed by admin.\\r\\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\\r\\n * @param timerAddress Timer address to set.\\r\\n */\\r\\n constructor(\\r\\n address _crossDomainAdmin,\\r\\n address _hubPool,\\r\\n address _wrappedNativeTokenAddress,\\r\\n address timerAddress\\r\\n ) Testable(timerAddress) {\\r\\n _setCrossDomainAdmin(_crossDomainAdmin);\\r\\n _setHubPool(_hubPool);\\r\\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\\r\\n }\\r\\n\\r\\n /****************************************\\r\\n * MODIFIERS *\\r\\n ****************************************/\\r\\n\\r\\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\\r\\n // appropriately.\\r\\n modifier onlyAdmin() {\\r\\n _requireAdminSender();\\r\\n _;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * ADMIN FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Change cross domain admin address. Callable by admin only.\\r\\n * @param newCrossDomainAdmin New cross domain admin.\\r\\n */\\r\\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\\r\\n _setCrossDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change L1 hub pool address. Callable by admin only.\\r\\n * @param newHubPool New hub pool.\\r\\n */\\r\\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\\r\\n _setHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\\r\\n * @param originToken Token that depositor can deposit to this contract.\\r\\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\\r\\n * @param enabled True to enable deposits, False otherwise.\\r\\n */\\r\\n function setEnableRoute(\\r\\n address originToken,\\r\\n uint256 destinationChainId,\\r\\n bool enabled\\r\\n ) public override onlyAdmin nonReentrant {\\r\\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\\r\\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\\r\\n * @param newDepositQuoteTimeBuffer New quote time buffer.\\r\\n */\\r\\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\\r\\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\\r\\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\\r\\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\\r\\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\\r\\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\\r\\n * executeRelayerRefundLeaf().\\r\\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\\r\\n * executeSlowRelayLeaf().\\r\\n */\\r\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\\r\\n uint32 rootBundleId = uint32(rootBundles.length);\\r\\n RootBundle storage rootBundle = rootBundles.push();\\r\\n rootBundle.relayerRefundRoot = relayerRefundRoot;\\r\\n rootBundle.slowRelayRoot = slowRelayRoot;\\r\\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\\r\\n * SpokePool.\\r\\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\\r\\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\\r\\n */\\r\\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\\r\\n delete rootBundles[rootBundleId];\\r\\n emit EmergencyDeleteRootBundle(rootBundleId);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DEPOSITOR FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\r\\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\r\\n * token mapping is stored on the L1 HubPool.\\r\\n * @notice The caller must first approve this contract to spend amount of originToken.\\r\\n * @notice The originToken => destinationChainId must be enabled.\\r\\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\\r\\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\r\\n * @param recipient Address to receive funds at on destination chain.\\r\\n * @param originToken Token to lock into this contract to initiate deposit.\\r\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\r\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\r\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\r\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\r\\n * to LP pool on HubPool.\\r\\n */\\r\\n function deposit(\\r\\n address recipient,\\r\\n address originToken,\\r\\n uint256 amount,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 quoteTimestamp\\r\\n ) public payable override nonReentrant {\\r\\n // Check that deposit route is enabled.\\r\\n require(enabledDepositRoutes[originToken][destinationChainId], \\\"Disabled route\\\");\\r\\n\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees.\\r\\n require(relayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\\r\\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\\r\\n // buffer of this contract's block time to allow for this variance.\\r\\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\\r\\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\\r\\n require(\\r\\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\\r\\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\\r\\n \\\"invalid quote time\\\"\\r\\n );\\r\\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\\r\\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\\r\\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\\r\\n require(msg.value == amount, \\\"msg.value must match amount\\\");\\r\\n wrappedNativeToken.deposit{ value: msg.value }();\\r\\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\\r\\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\\r\\n // In this case the msg.value will be set to 0, indicating a \\\"normal\\\" ERC20 bridging action.\\r\\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\\r\\n\\r\\n _emitDeposit(\\r\\n amount,\\r\\n chainId(),\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n numberOfDeposits,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n msg.sender\\r\\n );\\r\\n\\r\\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\\r\\n // @dev: Use pre-increment to save gas:\\r\\n // i++ --> Load, Store, Add, Store\\r\\n // ++i --> Load, Add, Store\\r\\n ++numberOfDeposits;\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\\r\\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\\r\\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\\r\\n * update fee message.\\r\\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\\r\\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\\r\\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\\r\\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\\r\\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\\r\\n * did in fact submit a relay.\\r\\n * @param newRelayerFeePct New relayer fee that relayers can use.\\r\\n * @param depositId Deposit to update fee for that originated in this contract.\\r\\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\\r\\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\\r\\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\\r\\n */\\r\\n function speedUpDeposit(\\r\\n address depositor,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n require(newRelayerFeePct < 0.5e18, \\\"invalid relayer fee\\\");\\r\\n\\r\\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\\r\\n // from the following event to submit a fill with an updated fee %.\\r\\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * RELAYER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\\r\\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\\r\\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\\r\\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\\r\\n * then relayer will not receive any refund.\\r\\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\\r\\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\\r\\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\\r\\n * as described in a UMIP linked to the HubPool's identifier.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n */\\r\\n function fillRelay(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId\\r\\n ) public nonReentrant {\\r\\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\\r\\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\\r\\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\\r\\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\\r\\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\\r\\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\\r\\n * send recipient the full relay amount.\\r\\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\\r\\n * passed.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param depositorSignature Depositor-signed message containing updated fee %.\\r\\n */\\r\\n function fillRelayWithUpdatedFee(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 maxTokensToSend,\\r\\n uint256 repaymentChainId,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) public override nonReentrant {\\r\\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\\r\\n\\r\\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: chainId()\\r\\n });\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\\r\\n\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * DATA WORKER FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\\r\\n * relay to the recipient, less fees.\\r\\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\\r\\n * the caller from executing a slow relay intended for another chain on this chain.\\r\\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\\r\\n * @param recipient Specified recipient on this chain.\\r\\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\\r\\n * and this chain ID via a mapping on the HubPool.\\r\\n * @param amount Full size of the deposit.\\r\\n * @param originChainId Chain of SpokePool where deposit originated.\\r\\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\\r\\n * quote time.\\r\\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\\r\\n * @param depositId Unique deposit ID on origin spoke pool.\\r\\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\\r\\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\\r\\n */\\r\\n function executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeSlowRelayLeaf(\\r\\n depositor,\\r\\n recipient,\\r\\n destinationToken,\\r\\n amount,\\r\\n originChainId,\\r\\n chainId(),\\r\\n realizedLpFeePct,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n rootBundleId,\\r\\n proof\\r\\n );\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\\r\\n * sent to the recipient plus a relayer fee.\\r\\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\\r\\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\\r\\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\\r\\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\\r\\n */\\r\\n function executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) public virtual override nonReentrant {\\r\\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * VIEW FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n /**\\r\\n * @notice Returns chain ID for this network.\\r\\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\\r\\n */\\r\\n function chainId() public view virtual override returns (uint256) {\\r\\n return block.chainid;\\r\\n }\\r\\n\\r\\n /**************************************\\r\\n * INTERNAL FUNCTIONS *\\r\\n **************************************/\\r\\n\\r\\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\\r\\n // transfers.\\r\\n function _executeRelayerRefundLeaf(\\r\\n uint32 rootBundleId,\\r\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n // Check integrity of leaf structure:\\r\\n require(relayerRefundLeaf.chainId == chainId(), \\\"Invalid chainId\\\");\\r\\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \\\"invalid leaf\\\");\\r\\n\\r\\n RootBundle storage rootBundle = rootBundles[rootBundleId];\\r\\n\\r\\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\\r\\n // Note: This should revert if the relayerRefundRoot is uninitialized.\\r\\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \\\"Bad Proof\\\");\\r\\n\\r\\n // Verify the leafId in the leaf has not yet been claimed.\\r\\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \\\"Already claimed\\\");\\r\\n\\r\\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\\r\\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\\r\\n\\r\\n // Send each relayer refund address the associated refundAmount for the L2 token address.\\r\\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\\r\\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\\r\\n for (uint32 i = 0; i < length; ) {\\r\\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\\r\\n if (amount > 0)\\r\\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\\r\\n\\r\\n // OK because we assume refund array length won't be > types(uint32).max.\\r\\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\\r\\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\\r\\n // not make it to this stage.\\r\\n\\r\\n unchecked {\\r\\n ++i;\\r\\n }\\r\\n }\\r\\n\\r\\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\\r\\n // chain-specific bridging method.\\r\\n if (relayerRefundLeaf.amountToReturn > 0) {\\r\\n _bridgeTokensToHubPool(relayerRefundLeaf);\\r\\n\\r\\n emit TokensBridged(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n emit ExecutedRelayerRefundRoot(\\r\\n relayerRefundLeaf.amountToReturn,\\r\\n relayerRefundLeaf.chainId,\\r\\n relayerRefundLeaf.refundAmounts,\\r\\n rootBundleId,\\r\\n relayerRefundLeaf.leafId,\\r\\n relayerRefundLeaf.l2TokenAddress,\\r\\n relayerRefundLeaf.refundAddresses,\\r\\n msg.sender\\r\\n );\\r\\n }\\r\\n\\r\\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\\r\\n function _executeSlowRelayLeaf(\\r\\n address depositor,\\r\\n address recipient,\\r\\n address destinationToken,\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 realizedLpFeePct,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 rootBundleId,\\r\\n bytes32[] memory proof\\r\\n ) internal {\\r\\n RelayData memory relayData = RelayData({\\r\\n depositor: depositor,\\r\\n recipient: recipient,\\r\\n destinationToken: destinationToken,\\r\\n amount: amount,\\r\\n originChainId: originChainId,\\r\\n destinationChainId: destinationChainId,\\r\\n realizedLpFeePct: realizedLpFeePct,\\r\\n relayerFeePct: relayerFeePct,\\r\\n depositId: depositId\\r\\n });\\r\\n\\r\\n require(\\r\\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\\r\\n \\\"Invalid proof\\\"\\r\\n );\\r\\n\\r\\n bytes32 relayHash = _getRelayHash(relayData);\\r\\n\\r\\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\\r\\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\\r\\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\\r\\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\\r\\n\\r\\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\\r\\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\\r\\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\\r\\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\\r\\n }\\r\\n\\r\\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\\r\\n require(newCrossDomainAdmin != address(0), \\\"Bad bridge router address\\\");\\r\\n crossDomainAdmin = newCrossDomainAdmin;\\r\\n emit SetXDomainAdmin(newCrossDomainAdmin);\\r\\n }\\r\\n\\r\\n function _setHubPool(address newHubPool) internal {\\r\\n require(newHubPool != address(0), \\\"Bad hub pool address\\\");\\r\\n hubPool = newHubPool;\\r\\n emit SetHubPool(newHubPool);\\r\\n }\\r\\n\\r\\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\\r\\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\\r\\n\\r\\n function _verifyUpdateRelayerFeeMessage(\\r\\n address depositor,\\r\\n uint256 originChainId,\\r\\n uint64 newRelayerFeePct,\\r\\n uint32 depositId,\\r\\n bytes memory depositorSignature\\r\\n ) internal view {\\r\\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\\r\\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\\r\\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\\r\\n // in case this contract is upgraded.\\r\\n // Note: we use encode instead of encodePacked because it is more secure, more in the \\\"warning\\\" section\\r\\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\\r\\n bytes32 expectedDepositorMessageHash = keccak256(\\r\\n abi.encode(\\\"ACROSS-V2-FEE-1.0\\\", newRelayerFeePct, depositId, originChainId)\\r\\n );\\r\\n\\r\\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\\r\\n // If the depositor signed a message with a different updated fee (or any other param included in the\\r\\n // above keccak156 hash), then this will revert.\\r\\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\\r\\n\\r\\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\\r\\n }\\r\\n\\r\\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\\r\\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\\r\\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\\r\\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\\r\\n function _verifyDepositorUpdateFeeMessage(\\r\\n address depositor,\\r\\n bytes32 ethSignedMessageHash,\\r\\n bytes memory depositorSignature\\r\\n ) internal view virtual {\\r\\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\\r\\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\\r\\n // chain does not have a parallel on this destination chain.\\r\\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \\\"invalid signature\\\");\\r\\n }\\r\\n\\r\\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (1e18 * amount) / (1e18 - feesPct);\\r\\n }\\r\\n\\r\\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\\r\\n return (amount * (1e18 - feesPct)) / 1e18;\\r\\n }\\r\\n\\r\\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\\r\\n return keccak256(abi.encode(relayData));\\r\\n }\\r\\n\\r\\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\\r\\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\\r\\n if (address(to).isContract()) {\\r\\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\\r\\n } else {\\r\\n wrappedNativeToken.withdraw(amount);\\r\\n to.transfer(amount);\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\\r\\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\\r\\n * and send to the recipient.\\r\\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\\r\\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\\r\\n */\\r\\n function _fillRelay(\\r\\n bytes32 relayHash,\\r\\n RelayData memory relayData,\\r\\n uint256 maxTokensToSend,\\r\\n uint64 updatableRelayerFeePct,\\r\\n bool useContractFunds\\r\\n ) internal returns (uint256 fillAmountPreFees) {\\r\\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\\r\\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\\r\\n // computing the amount pre fees runs into divide-by-0 issues.\\r\\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \\\"invalid fees\\\");\\r\\n\\r\\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\\r\\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\\r\\n require(relayFills[relayHash] < relayData.amount, \\\"relay filled\\\");\\r\\n\\r\\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\\r\\n if (maxTokensToSend == 0) return 0;\\r\\n\\r\\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\\r\\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\\r\\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\\r\\n // of the full relay size, the caller would need to send 10 tokens to the user.\\r\\n fillAmountPreFees = _computeAmountPreFees(\\r\\n maxTokensToSend,\\r\\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\\r\\n );\\r\\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\\r\\n // we'll pull exactly enough tokens to complete the relay.\\r\\n uint256 amountToSend = maxTokensToSend;\\r\\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\\r\\n if (amountRemainingInRelay < fillAmountPreFees) {\\r\\n fillAmountPreFees = amountRemainingInRelay;\\r\\n\\r\\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\\r\\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\\r\\n // this is a slow relay.\\r\\n amountToSend = _computeAmountPostFees(\\r\\n fillAmountPreFees,\\r\\n relayData.realizedLpFeePct + updatableRelayerFeePct\\r\\n );\\r\\n }\\r\\n\\r\\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\\r\\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\\r\\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\\r\\n relayFills[relayHash] += fillAmountPreFees;\\r\\n\\r\\n // If relay token is wrappedNativeToken then unwrap and send native token.\\r\\n if (relayData.destinationToken == address(wrappedNativeToken)) {\\r\\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\\r\\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\\r\\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\\r\\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\\r\\n // need to unwrap it to native token before sending to the user.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\\r\\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\\r\\n // Else, this is a normal ERC20 token. Send to recipient.\\r\\n } else {\\r\\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\\r\\n if (!useContractFunds)\\r\\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\\r\\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\\r\\n }\\r\\n }\\r\\n\\r\\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\\r\\n function _emitFillRelay(\\r\\n bytes32 relayHash,\\r\\n uint256 fillAmount,\\r\\n uint256 repaymentChainId,\\r\\n uint64 relayerFeePct,\\r\\n RelayData memory relayData,\\r\\n bool isSlowRelay\\r\\n ) internal {\\r\\n emit FilledRelay(\\r\\n relayHash,\\r\\n relayData.amount,\\r\\n relayFills[relayHash],\\r\\n fillAmount,\\r\\n repaymentChainId,\\r\\n relayData.originChainId,\\r\\n relayData.destinationChainId,\\r\\n relayerFeePct,\\r\\n relayData.realizedLpFeePct,\\r\\n relayData.depositId,\\r\\n relayData.destinationToken,\\r\\n msg.sender,\\r\\n relayData.depositor,\\r\\n relayData.recipient,\\r\\n isSlowRelay\\r\\n );\\r\\n }\\r\\n\\r\\n function _emitDeposit(\\r\\n uint256 amount,\\r\\n uint256 originChainId,\\r\\n uint256 destinationChainId,\\r\\n uint64 relayerFeePct,\\r\\n uint32 depositId,\\r\\n uint32 quoteTimestamp,\\r\\n address originToken,\\r\\n address recipient,\\r\\n address depositor\\r\\n ) internal {\\r\\n emit FundsDeposited(\\r\\n amount,\\r\\n originChainId,\\r\\n destinationChainId,\\r\\n relayerFeePct,\\r\\n depositId,\\r\\n quoteTimestamp,\\r\\n originToken,\\r\\n recipient,\\r\\n depositor\\r\\n );\\r\\n }\\r\\n\\r\\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\\r\\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\\r\\n // L1, this would just be the same admin of the HubPool.\\r\\n function _requireAdminSender() internal virtual;\\r\\n\\r\\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\\r\\n receive() external payable {}\\r\\n}\\r\\n\",\"keccak256\":\"0xeb7a64b4ec0592d18254c802d35779fc6aabfca5c6817c52b4344a3946e5654e\",\"license\":\"GPL-3.0-only\"},\"contracts/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\\n // chain validator can choose when to refund slow relayers.\\n struct RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // The corresponding token address on the destination chain.\\n address destinationToken;\\n // The total relay amount before fees are taken out.\\n uint256 amount;\\n // Origin chain id.\\n uint256 originChainId;\\n // Destination chain id.\\n uint256 destinationChainId;\\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\\n // and the HubPool's utilization.\\n uint64 realizedLpFeePct;\\n // The relayer fee percentage specified in the deposit.\\n uint64 relayerFeePct;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x256 leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n uint64 relayerFeePct,\\n uint32 quoteTimestamp\\n ) external payable;\\n\\n function speedUpDeposit(\\n address depositor,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function fillRelay(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId\\n ) external;\\n\\n function fillRelayWithUpdatedFee(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 maxTokensToSend,\\n uint256 repaymentChainId,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint64 newRelayerFeePct,\\n uint32 depositId,\\n bytes memory depositorSignature\\n ) external;\\n\\n function executeSlowRelayLeaf(\\n address depositor,\\n address recipient,\\n address destinationToken,\\n uint256 amount,\\n uint256 originChainId,\\n uint64 realizedLpFeePct,\\n uint64 relayerFeePct,\\n uint32 depositId,\\n uint32 rootBundleId,\\n bytes32[] memory proof\\n ) external;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external;\\n\\n function chainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xbd436408b1294166c3459d9f23f80358ae99e95b95b474a99525949e3bf8569d\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes calldata message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x49ebe1ceb1ac746444ff74eba5e59510c964fce92c89ddbc95ac834a28a89640\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60a06040526002805463ffffffff60a01b1916604b60a31b1790553480156200002757600080fd5b5060405162004676380380620046768339810160408190526200004a9162000260565b600080546001600160a81b0319166001600160a01b03831617600160a01b179055338383836200007a84620000a9565b62000085836200014f565b506001600160a01b031660805250620000a0905033620001f1565b505050620002aa565b6001600160a01b038116620001055760405162461bcd60e51b815260206004820152601960248201527f4261642062726964676520726f7574657220616464726573730000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b6001600160a01b038116620001a75760405162461bcd60e51b815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401620000fc565b600280546001600160a01b0319166001600160a01b0383169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200025b57600080fd5b919050565b6000806000606084860312156200027657600080fd5b620002818462000243565b9250620002916020850162000243565b9150620002a16040850162000243565b90509250925092565b60805161438d620002e9600039600081816101d901528181610ce601528181610daf0152818161236501528181612bde0152612c34015261438d6000f3fe6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b50610245610240366004613678565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613774565b6106b0565b3480156102a057600080fd5b506102456102af36600461378f565b61073d565b3480156102c057600080fd5b506102456102cf3660046137b6565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137f6565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b610245610325366004613829565b610ab1565b34801561033657600080fd5b5061024561034536600461388f565b610f28565b34801561035657600080fd5b506103856103653660046138b1565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138db565b6110cf565b34801561044d57600080fd5b5061024561045c36600461378f565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e6366004613979565b6112ff565b60405161021c9190613a64565b34801561050457600080fd5b50610245610513366004613ae4565b6114d9565b34801561052457600080fd5b50610245610533366004613774565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c42565b6115ab565b34801561059157600080fd5b506105a56105a036600461378f565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d536600461378f565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613774565b611737565b34801561061357600080fd5b50610245610622366004613cb1565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611e17565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e98565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611e17565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611e17565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d8f565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dd7565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613dfc565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f84565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612060565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e24565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611e17565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120f1565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612168565b905060006111c782848b886000612198565b90506111d882828a88876000612445565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611e17565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e47565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134bc565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e47565b90506020028101906113eb9190613e76565b6040516113f9929190613edb565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613eeb565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b808484815181106114b2576114b2613e47565b6020026020010181905250505080806114ca90613f6c565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61257a565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611e17565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126f9565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127e5565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613fa4565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120f1565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127e5565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612168565b9050600061196982848d896000612198565b905061197a82828c89876000612445565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e47565b90600052602060002090600302019050611b6d81600101548484612882565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128bf565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff16612900565b60408301515160005b8163ffffffff168163ffffffff161015611d1157600085604001518263ffffffff1681518110611ca357611ca3613e47565b602002602001015190506000811115611d0857611d088660a001518363ffffffff1681518110611cd557611cd5613e47565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50600101611c71565b50835115611daa57611d2284612994565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611da192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611e08959493929190614048565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a38565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008160405160200161217b91906140a6565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121d057506706f05b59d3b200008560c0015167ffffffffffffffff16105b612236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106122b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122c15750600061243c565b6122da84848760c001516122d5919061414d565b612b44565b600087815260056020526040812054606088015192935086926122fd9190614170565b9050828110156123265780925061232383868960c0015161231e919061414d565b612b7e565b91505b60008881526005602052604081208054859290612344908490614187565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123cc57836123b95760408701516123b99073ffffffffffffffffffffffffffffffffffffffff16333085611f84565b6123c7876020015183612ba7565b612439565b83612406576123c7338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f84909392919063ffffffff16565b612439876020015183896040015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f60405161256a9c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264f60038463ffffffff168154811061263657612636613e47565b9060005260206000209060030201600001548284612ce8565b6126b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126c082612168565b905060006126d78284856060015160006001612198565b90506126e98282600080876001612445565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286c82612d00565b9050612879878285612d3b565b50505050505050565b60006128b582858560405160200161289a919061419f565b60405160208183030381529060405280519060200120612dd9565b90505b9392505050565b6000806128ce61010084614269565b905060006128de6101008561427d565b6000928352602095909552506040902054600190931b92831690921492915050565b600061290e61010083614269565b9050600061291e6101008461427d565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fde565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614291565b6000612a9a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612def9092919063ffffffff16565b8051909150156106ab5780806020019051810190612ab89190614291565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b5882670de0b6b3a76400006142ae565b67ffffffffffffffff16612b7484670de0b6b3a76400006142cf565b6128b89190614269565b6000670de0b6b3a7640000612b9383826142ae565b612b749067ffffffffffffffff16856142cf565b73ffffffffffffffffffffffffffffffffffffffff82163b15612c055761103e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838361293e565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8d57600080fd5b505af1158015612ca1573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128b582858560405160200161289a91906140a6565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161217b565b612d458282612dfe565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612de68584612e22565b14949350505050565b60606128b58484600085612e8e565b6000806000612e0d8585613024565b91509150612e1a81613092565b509392505050565b600081815b8451811015612e1a576000858281518110612e4457612e44613e47565b60200260200101519050808311612e6a5760008381526020829052604090209250612e7b565b600081815260208490526040902092505b5080612e8681613f6c565b915050612e27565b606082471015612f20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fc7919061430c565b60006040518083038185875af1925050503d8060008114613004576040519150601f19603f3d011682016040523d82523d6000602084013e613009565b606091505b50915091506130198282866132e6565b979650505050505050565b600080825160410361305a5760208301516040840151606085015160001a61304e87828585613339565b9450945050505061308b565b82516040036130835760208301516040840151613078868383613451565b93509350505061308b565b506000905060025b9250929050565b60008160048111156130a6576130a6614328565b036130ae5750565b60018160048111156130c2576130c2614328565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b600281600481111561313d5761313d614328565b036131a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131b8576131b8614328565b03613245576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561325957613259614328565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132f55750816128b8565b8251156133055782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156133705750600090506003613448565b8460ff16601b1415801561338857508460ff16601c14155b156133995750600090506004613448565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133ed573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661344157600060019250925050613448565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161348760ff86901c601b614187565b905061349587828885613339565b935093505050935093915050565b803563ffffffff811681146134b757600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561350e5761350e6134bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561355b5761355b6134bc565b604052919050565b600067ffffffffffffffff82111561357d5761357d6134bc565b5060051b60200190565b600082601f83011261359857600080fd5b813560206135ad6135a883613563565b613514565b82815260059290921b840181019181810190868411156135cc57600080fd5b8286015b848110156135e757803583529183019183016135d0565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134b757600080fd5b600082601f83011261362757600080fd5b813560206136376135a883613563565b82815260059290921b8401810191818101908684111561365657600080fd5b8286015b848110156135e75761366b816135f2565b835291830191830161365a565b60008060006060848603121561368d57600080fd5b613696846134a3565b9250602084013567ffffffffffffffff808211156136b357600080fd5b9085019060c082880312156136c757600080fd5b6136cf6134eb565b82358152602083013560208201526040830135828111156136ef57600080fd5b6136fb89828601613587565b60408301525061370d606084016134a3565b606082015261371e608084016135f2565b608082015260a08301358281111561373557600080fd5b61374189828601613616565b60a0830152509350604086013591508082111561375d57600080fd5b5061376a86828701613587565b9150509250925092565b60006020828403121561378657600080fd5b6128b8826135f2565b6000602082840312156137a157600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137cb57600080fd5b6137d4846135f2565b92506020840135915060408401356137eb816137a8565b809150509250925092565b60006020828403121561380857600080fd5b6128b8826134a3565b803567ffffffffffffffff811681146134b757600080fd5b60008060008060008060c0878903121561384257600080fd5b61384b876135f2565b9550613859602088016135f2565b9450604087013593506060870135925061387560808801613811565b915061388360a088016134a3565b90509295509295509295565b600080604083850312156138a257600080fd5b50508035926020909101359150565b600080604083850312156138c457600080fd5b6138cd836135f2565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138fb57600080fd5b6139048b6135f2565b995061391260208c016135f2565b985061392060408c016135f2565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061394a60e08c01613811565b92506139596101008c01613811565b91506139686101208c016134a3565b90509295989b9194979a5092959850565b6000806020838503121561398c57600080fd5b823567ffffffffffffffff808211156139a457600080fd5b818501915085601f8301126139b857600080fd5b8135818111156139c757600080fd5b8660208260051b85010111156139dc57600080fd5b60209290920196919550909350505050565b60005b83811015613a095781810151838201526020016139f1565b838111156117035750506000910152565b60008151808452613a328160208601602086016139ee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613ad7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613ac5858351613a1a565b94509285019290850190600101613a8b565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613b0457600080fd5b613b0d8b6135f2565b9950613b1b60208c016135f2565b9850613b2960408c016135f2565b975060608b0135965060808b01359550613b4560a08c01613811565b9450613b5360c08c01613811565b9350613b6160e08c016134a3565b9250613b706101008c016134a3565b91506101208b013567ffffffffffffffff811115613b8d57600080fd5b613b998d828e01613587565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bc557613bc56134bc565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0257600080fd5b8135613c106135a882613bab565b818152846020838601011115613c2557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c5857600080fd5b613c61856135f2565b9350613c6f60208601613811565b9250613c7d604086016134a3565b9150606085013567ffffffffffffffff811115613c9957600080fd5b613ca587828801613bf1565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cd457600080fd5b613cdd8d6135f2565b9b50613ceb60208e016135f2565b9a50613cf960408e016135f2565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d2360e08e01613811565b9450613d326101008e01613811565b9350613d416101208e01613811565b9250613d506101408e016134a3565b915067ffffffffffffffff6101608e01351115613d6c57600080fd5b613d7d8e6101608f01358f01613bf1565b90509295989b509295989b509295989b565b600060208284031215613da157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613df457613df4613da8565b039392505050565b600063ffffffff808316818516808303821115613e1b57613e1b613da8565b01949350505050565b600063ffffffff808316818103613e3d57613e3d613da8565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613eab57600080fd5b83018035915067ffffffffffffffff821115613ec657600080fd5b60200191503681900382131561308b57600080fd5b8183823760009101908152919050565b600060208284031215613efd57600080fd5b815167ffffffffffffffff811115613f1457600080fd5b8201601f81018413613f2557600080fd5b8051613f336135a882613bab565b818152856020838501011115613f4857600080fd5b61243c8260208301602086016139ee565b6020815260006128b86020830184613a1a565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9d57613f9d613da8565b5060010190565b67ffffffffffffffff831681526040602082015260006128b56040830184613a1a565b600081518084526020808501945080840160005b83811015613ff757815187529582019590820190600101613fdb565b509495945050505050565b600081518084526020808501945080840160005b83811015613ff757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614016565b85815260a06020820152600061406160a0830187613fc7565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140908287614002565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411b60c084018267ffffffffffffffff169052565b5060e083015161413760e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1b57613e1b613da8565b60008282101561418257614182613da8565b500390565b6000821982111561419a5761419a613da8565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141cf60e0840182613fc7565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261243c8282614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826142785761427861423a565b500490565b60008261428c5761428c61423a565b500690565b6000602082840312156142a357600080fd5b81516128b8816137a8565b600067ffffffffffffffff83811690831681811015613df457613df4613da8565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430757614307613da8565b500290565b6000825161431e8184602087016139ee565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220355f32bdb028a28cbe50e81ac06a0ec2427ffb0f4e0b67010c2cd12bb9b1455664736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106101bb5760003560e01c806389a153cc116100ec578063de7eba781161008a578063ee2a53f811610064578063ee2a53f814610585578063f06850f6146105ba578063f2fde38b146105e7578063ffc351a31461060757600080fd5b8063de7eba7814610518578063e190440214610538578063e282d5b91461056557600080fd5b80639a8a0592116100c65780639a8a05921461048c578063a1244c671461049f578063ac9650d8146104d8578063be3576ee146104f857600080fd5b806389a153cc146104215780638a7860ce146104415780638da5cb5b1461046157600080fd5b806329cb924d116101595780635249fef1116101335780635249fef11461034a5780635285e0581461039557806357f6dcb8146103c2578063715018a61461040c57600080fd5b806329cb924d146102f45780634922897814610317578063493a4f841461032a57600080fd5b80631dfb2d02116101955780631dfb2d021461027457806322f8e56614610294578063272751c7146102b45780632752042e146102d457600080fd5b806317fcb39b146101c75780631b3d5559146102255780631c39c38d1461024757600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b50610245610240366004613678565b610627565b005b34801561025357600080fd5b506000546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561028057600080fd5b5061024561028f366004613774565b6106b0565b3480156102a057600080fd5b506102456102af36600461378f565b61073d565b3480156102c057600080fd5b506102456102cf3660046137b6565b6107e6565b3480156102e057600080fd5b506102456102ef3660046137f6565b6108f8565b34801561030057600080fd5b506103096109f9565b60405190815260200161021c565b610245610325366004613829565b610ab1565b34801561033657600080fd5b5061024561034536600461388f565b610f28565b34801561035657600080fd5b506103856103653660046138b1565b600460209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021c565b3480156103a157600080fd5b506001546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ce57600080fd5b506002546103f79074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021c565b34801561041857600080fd5b50610245611042565b34801561042d57600080fd5b5061024561043c3660046138db565b6110cf565b34801561044d57600080fd5b5061024561045c36600461378f565b61122b565b34801561046d57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166101fb565b34801561049857600080fd5b5046610309565b3480156104ab57600080fd5b506002546103f7907801000000000000000000000000000000000000000000000000900463ffffffff1681565b6104eb6104e6366004613979565b6112ff565b60405161021c9190613a64565b34801561050457600080fd5b50610245610513366004613ae4565b6114d9565b34801561052457600080fd5b50610245610533366004613774565b611565565b34801561054457600080fd5b506002546101fb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057157600080fd5b50610245610580366004613c42565b6115ab565b34801561059157600080fd5b506105a56105a036600461378f565b611709565b6040805192835260208301919091520161021c565b3480156105c657600080fd5b506103096105d536600461378f565b60056020526000908152604090205481565b3480156105f357600080fd5b50610245610602366004613774565b611737565b34801561061357600080fd5b50610245610622366004613cb1565b611864565b61062f6119cf565b61065c600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610667838383611a53565b6106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b6106b8611e17565b6106c06119cf565b6106ed600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f681611e98565b61073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1661075f57600080fd5b6000546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b5050505050565b6107ee611e17565b6107f66119cf565b610823600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832086845282529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182528492917f0a21fdd43d0ad0c62689ee7230a47309a050755bcc52eba00310add65297692a910160405180910390a36106ab600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b610900611e17565b6109086119cf565b610935600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f0e55dd180fa793d9036c804d0a116e6a7617a48e72cee1f83d92793a793fcc039060200160405180910390a161073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615610aac5760008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613d8f565b905090565b504290565b610ab96119cf565b610ae6600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832086845290915290205460ff16610b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f44697361626c656420726f75746500000000000000000000000000000000000060448201526064015b60405180910390fd5b6706f05b59d3b200008267ffffffffffffffff1610610c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b600254610c2b9074010000000000000000000000000000000000000000900463ffffffff1682613dd7565b63ffffffff16610c396109f9565b10158015610c7e5750600254610c6d9074010000000000000000000000000000000000000000900463ffffffff1682613dfc565b63ffffffff16610c7b6109f9565b11155b610ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642071756f74652074696d6500000000000000000000000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16148015610d3f5750600034115b15610e3357833414610dad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d73672e76616c7565206d757374206d6174636820616d6f756e7400000000006044820152606401610b7c565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b5050505050610e55565b610e5573ffffffffffffffffffffffffffffffffffffffff8616333087611f84565b610e8c8446600254869086907801000000000000000000000000000000000000000000000000900463ffffffff16868b8d33612060565b60028054601890610ebe907801000000000000000000000000000000000000000000000000900463ffffffff16613e24565b91906101000a81548163ffffffff021916908363ffffffff160217905550610f20600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050565b610f30611e17565b610f386119cf565b610f65600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003805460018101825560008281529181027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c81018590557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01838155604051919290918491869163ffffffff8616917fc86ba04c55bc5eb2f2876b91c438849a296dbec7b08751c3074d92e04f0a77af91a4505061103e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b6110cd60006120f1565b565b6110d76119cf565b611104600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60006040518061012001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018681526020016111794690565b81526020018567ffffffffffffffff1681526020018467ffffffffffffffff1681526020018363ffffffff16815250905060006111b582612168565b905060006111c782848b886000612198565b90506111d882828a88876000612445565b50505061121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050505050505050565b611233611e17565b61123b6119cf565b611268600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6003818154811061127b5761127b613e47565b60009182526020822060039091020181815560010181905560405182917f3569b846531b754c99cb80df3f49cd72fa6fe106aaee5ab8e0caf35a9d7ce88d91a261073a600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60603415611369576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c756500000000006044820152606401610b7c565b8167ffffffffffffffff811115611382576113826134bc565b6040519080825280602002602001820160405280156113b557816020015b60608152602001906001900390816113a05790505b50905060005b828110156114d257600080308686858181106113d9576113d9613e47565b90506020028101906113eb9190613e76565b6040516113f9929190613edb565b600060405180830381855af49150503d8060008114611434576040519150601f19603f3d011682016040523d82523d6000602084013e611439565b606091505b50915091508161149f5760448151101561145257600080fd5b6004810190508080602001905181019061146c9190613eeb565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b808484815181106114b2576114b2613e47565b6020026020010181905250505080806114ca90613f6c565b9150506113bb565b5092915050565b6114e16119cf565b61150e600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6115218a8a8a8a8a468b8b8b8b8b61257a565b61121f600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b61156d611e17565b6115756119cf565b6115a2600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6106f6816126f9565b6115b36119cf565b6115e0600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6706f05b59d3b200008367ffffffffffffffff161061165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642072656c6179657220666565000000000000000000000000006044820152606401610b7c565b61166884468585856127e5565b8373ffffffffffffffffffffffffffffffffffffffff168263ffffffff167fb9de16bf376724405019a10ef4fedac57fecd292bf86c08d81d7c42d394d5d3785846040516116b7929190613fa4565b60405180910390a3611703600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6003818154811061171957600080fd5b60009182526020909120600390910201805460019091015490915082565b60065473ffffffffffffffffffffffffffffffffffffffff1633146117b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff811661185b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b7c565b61073a816120f1565b61186c6119cf565b611899600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6118a68c878585856127e5565b60006040518061012001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b815260200188815260200161191b4690565b81526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018463ffffffff168152509050600061195782612168565b9050600061196982848d896000612198565b905061197a82828c89876000612445565b5050506119c1600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050505050505050505050565b60005474010000000000000000000000000000000000000000900460ff166110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b7c565b46826020015114611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c696420636861696e496400000000000000000000000000000000006044820152606401610b7c565b8160400151518260a001515114611b33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206c65616600000000000000000000000000000000000000006044820152606401610b7c565b600060038463ffffffff1681548110611b4e57611b4e613e47565b90600052602060002090600302019050611b6d81600101548484612882565b611bd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4261642050726f6f6600000000000000000000000000000000000000000000006044820152606401610b7c565b611bea81600201846060015163ffffffff166128bf565b15611c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920636c61696d656400000000000000000000000000000000006044820152606401610b7c565b611c6881600201846060015163ffffffff16612900565b60408301515160005b8163ffffffff168163ffffffff161015611d1157600085604001518263ffffffff1681518110611ca357611ca3613e47565b602002602001015190506000811115611d0857611d088660a001518363ffffffff1681518110611cd557611cd5613e47565b602002602001015182886080015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50600101611c71565b50835115611daa57611d2284612994565b836080015173ffffffffffffffffffffffffffffffffffffffff16846060015163ffffffff1685602001517f828fc203220356df8f072a91681caee7d5c75095e2a95e80ed5a14b384697f71876000015133604051611da192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a45b836060015163ffffffff168563ffffffff1685602001517ff8bd640004bcec1b89657020f561d0b070cbdf662d0b158db9dccb0a8301bfab8760000151886040015189608001518a60a0015133604051611e08959493929190614048565b60405180910390a45050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146110cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b7c565b73ffffffffffffffffffffffffffffffffffffffff8116611f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4261642068756220706f6f6c20616464726573730000000000000000000000006044820152606401610b7c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f1f17a88f67b0f49060a34bec1a4723a563620e6aa265eb640b5046dcee0759a090600090a250565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526117039085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a38565b604080518a8152602081018a905290810188905267ffffffffffffffff8716606082015263ffffffff858116608083015273ffffffffffffffffffffffffffffffffffffffff84811660a084015280841692908616918816907f4a4fc49abd237bfd7f4ac82d6c7a284c69daaea5154430cff04ad7482c6c42549060c00160405180910390a4505050505050505050565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008160405160200161217b91906140a6565b604051602081830303815290604052805190602001209050919050565b60006706f05b59d3b200008367ffffffffffffffff161080156121d057506706f05b59d3b200008560c0015167ffffffffffffffff16105b612236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f696e76616c6964206665657300000000000000000000000000000000000000006044820152606401610b7c565b6060850151600087815260056020526040902054106122b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f72656c61792066696c6c656400000000000000000000000000000000000000006044820152606401610b7c565b836000036122c15750600061243c565b6122da84848760c001516122d5919061414d565b612b44565b600087815260056020526040812054606088015192935086926122fd9190614170565b9050828110156123265780925061232383868960c0015161231e919061414d565b612b7e565b91505b60008881526005602052604081208054859290612344908490614187565b9091555050604087015173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116036123cc57836123b95760408701516123b99073ffffffffffffffffffffffffffffffffffffffff16333085611f84565b6123c7876020015183612ba7565b612439565b83612406576123c7338860200151848a6040015173ffffffffffffffffffffffffffffffffffffffff16611f84909392919063ffffffff16565b612439876020015183896040015173ffffffffffffffffffffffffffffffffffffffff1661293e9092919063ffffffff16565b50505b95945050505050565b816000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f1d59c1d19baf4b4de03cec9c844258e7ca2f2004975025eb14fe9a5e1d4e0d888560600151600560008c8152602001908152602001600020548a8a89608001518a60a001518c8c60c001518d61010001518e604001518f602001518f60405161256a9c9b9a999897969594939291909b8c5260208c019a909a5260408b019890985260608a0196909652608089019490945260a088019290925267ffffffffffffffff90811660c08801521660e086015263ffffffff1661010085015273ffffffffffffffffffffffffffffffffffffffff9081166101208501521661014083015215156101608201526101800190565b60405180910390a4505050505050565b60006040518061012001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018981526020018881526020018767ffffffffffffffff1681526020018667ffffffffffffffff1681526020018563ffffffff16815250905061264f60038463ffffffff168154811061263657612636613e47565b9060005260206000209060030201600001548284612ce8565b6126b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610b7c565b60006126c082612168565b905060006126d78284856060015160006001612198565b90506126e98282600080876001612445565b5050505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116612776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4261642062726964676520726f757465722061646472657373000000000000006044820152606401610b7c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fa9e8c42c9e7fca7f62755189a16b2f5314d43d8fb24e91ba54e6d65f9314e84990600090a250565b60408051608060208201819052601160a08301527f4143524f53532d56322d4645452d312e3000000000000000000000000000000060c083015267ffffffffffffffff86169282019290925263ffffffff8416606082015290810185905260009060e001604051602081830303815290604052805190602001209050600061286c82612d00565b9050612879878285612d3b565b50505050505050565b60006128b582858560405160200161289a919061419f565b60405160208183030381529060405280519060200120612dd9565b90505b9392505050565b6000806128ce61010084614269565b905060006128de6101008561427d565b6000928352602095909552506040902054600190931b92831690921492915050565b600061290e61010083614269565b9050600061291e6101008461427d565b600092835260209490945250604090208054600190931b90921790915550565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106ab9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611fde565b608081015160025482516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103e9190614291565b6000612a9a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612def9092919063ffffffff16565b8051909150156106ab5780806020019051810190612ab89190614291565b6106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b7c565b6000612b5882670de0b6b3a76400006142ae565b67ffffffffffffffff16612b7484670de0b6b3a76400006142cf565b6128b89190614269565b6000670de0b6b3a7640000612b9383826142ae565b612b749067ffffffffffffffff16856142cf565b73ffffffffffffffffffffffffffffffffffffffff82163b15612c055761103e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838361293e565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015612c8d57600080fd5b505af1158015612ca1573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8516925083156108fc02915083906000818181858888f193505050501580156106ab573d6000803e3d6000fd5b60006128b582858560405160200161289a91906140a6565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161217b565b612d458282612dfe565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146106ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610b7c565b600082612de68584612e22565b14949350505050565b60606128b58484600085612e8e565b6000806000612e0d8585613024565b91509150612e1a81613092565b509392505050565b600081815b8451811015612e1a576000858281518110612e4457612e44613e47565b60200260200101519050808311612e6a5760008381526020829052604090209250612e7b565b600081815260208490526040902092505b5080612e8681613f6c565b915050612e27565b606082471015612f20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b7c565b73ffffffffffffffffffffffffffffffffffffffff85163b612f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612fc7919061430c565b60006040518083038185875af1925050503d8060008114613004576040519150601f19603f3d011682016040523d82523d6000602084013e613009565b606091505b50915091506130198282866132e6565b979650505050505050565b600080825160410361305a5760208301516040840151606085015160001a61304e87828585613339565b9450945050505061308b565b82516040036130835760208301516040840151613078868383613451565b93509350505061308b565b506000905060025b9250929050565b60008160048111156130a6576130a6614328565b036130ae5750565b60018160048111156130c2576130c2614328565b03613129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b7c565b600281600481111561313d5761313d614328565b036131a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b7c565b60038160048111156131b8576131b8614328565b03613245576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b600481600481111561325957613259614328565b0361073a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b7c565b606083156132f55750816128b8565b8251156133055782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c9190613f59565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156133705750600090506003613448565b8460ff16601b1415801561338857508460ff16601c14155b156133995750600090506004613448565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156133ed573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661344157600060019250925050613448565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161348760ff86901c601b614187565b905061349587828885613339565b935093505050935093915050565b803563ffffffff811681146134b757600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561350e5761350e6134bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561355b5761355b6134bc565b604052919050565b600067ffffffffffffffff82111561357d5761357d6134bc565b5060051b60200190565b600082601f83011261359857600080fd5b813560206135ad6135a883613563565b613514565b82815260059290921b840181019181810190868411156135cc57600080fd5b8286015b848110156135e757803583529183019183016135d0565b509695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146134b757600080fd5b600082601f83011261362757600080fd5b813560206136376135a883613563565b82815260059290921b8401810191818101908684111561365657600080fd5b8286015b848110156135e75761366b816135f2565b835291830191830161365a565b60008060006060848603121561368d57600080fd5b613696846134a3565b9250602084013567ffffffffffffffff808211156136b357600080fd5b9085019060c082880312156136c757600080fd5b6136cf6134eb565b82358152602083013560208201526040830135828111156136ef57600080fd5b6136fb89828601613587565b60408301525061370d606084016134a3565b606082015261371e608084016135f2565b608082015260a08301358281111561373557600080fd5b61374189828601613616565b60a0830152509350604086013591508082111561375d57600080fd5b5061376a86828701613587565b9150509250925092565b60006020828403121561378657600080fd5b6128b8826135f2565b6000602082840312156137a157600080fd5b5035919050565b801515811461073a57600080fd5b6000806000606084860312156137cb57600080fd5b6137d4846135f2565b92506020840135915060408401356137eb816137a8565b809150509250925092565b60006020828403121561380857600080fd5b6128b8826134a3565b803567ffffffffffffffff811681146134b757600080fd5b60008060008060008060c0878903121561384257600080fd5b61384b876135f2565b9550613859602088016135f2565b9450604087013593506060870135925061387560808801613811565b915061388360a088016134a3565b90509295509295509295565b600080604083850312156138a257600080fd5b50508035926020909101359150565b600080604083850312156138c457600080fd5b6138cd836135f2565b946020939093013593505050565b6000806000806000806000806000806101408b8d0312156138fb57600080fd5b6139048b6135f2565b995061391260208c016135f2565b985061392060408c016135f2565b975060608b0135965060808b0135955060a08b0135945060c08b0135935061394a60e08c01613811565b92506139596101008c01613811565b91506139686101208c016134a3565b90509295989b9194979a5092959850565b6000806020838503121561398c57600080fd5b823567ffffffffffffffff808211156139a457600080fd5b818501915085601f8301126139b857600080fd5b8135818111156139c757600080fd5b8660208260051b85010111156139dc57600080fd5b60209290920196919550909350505050565b60005b83811015613a095781810151838201526020016139f1565b838111156117035750506000910152565b60008151808452613a328160208601602086016139ee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613ad7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613ac5858351613a1a565b94509285019290850190600101613a8b565b5092979650505050505050565b6000806000806000806000806000806101408b8d031215613b0457600080fd5b613b0d8b6135f2565b9950613b1b60208c016135f2565b9850613b2960408c016135f2565b975060608b0135965060808b01359550613b4560a08c01613811565b9450613b5360c08c01613811565b9350613b6160e08c016134a3565b9250613b706101008c016134a3565b91506101208b013567ffffffffffffffff811115613b8d57600080fd5b613b998d828e01613587565b9150509295989b9194979a5092959850565b600067ffffffffffffffff821115613bc557613bc56134bc565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0257600080fd5b8135613c106135a882613bab565b818152846020838601011115613c2557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613c5857600080fd5b613c61856135f2565b9350613c6f60208601613811565b9250613c7d604086016134a3565b9150606085013567ffffffffffffffff811115613c9957600080fd5b613ca587828801613bf1565b91505092959194509250565b6000806000806000806000806000806000806101808d8f031215613cd457600080fd5b613cdd8d6135f2565b9b50613ceb60208e016135f2565b9a50613cf960408e016135f2565b995060608d0135985060808d0135975060a08d0135965060c08d01359550613d2360e08e01613811565b9450613d326101008e01613811565b9350613d416101208e01613811565b9250613d506101408e016134a3565b915067ffffffffffffffff6101608e01351115613d6c57600080fd5b613d7d8e6101608f01358f01613bf1565b90509295989b509295989b509295989b565b600060208284031215613da157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff83811690831681811015613df457613df4613da8565b039392505050565b600063ffffffff808316818516808303821115613e1b57613e1b613da8565b01949350505050565b600063ffffffff808316818103613e3d57613e3d613da8565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613eab57600080fd5b83018035915067ffffffffffffffff821115613ec657600080fd5b60200191503681900382131561308b57600080fd5b8183823760009101908152919050565b600060208284031215613efd57600080fd5b815167ffffffffffffffff811115613f1457600080fd5b8201601f81018413613f2557600080fd5b8051613f336135a882613bab565b818152856020838501011115613f4857600080fd5b61243c8260208301602086016139ee565b6020815260006128b86020830184613a1a565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f9d57613f9d613da8565b5060010190565b67ffffffffffffffff831681526040602082015260006128b56040830184613a1a565b600081518084526020808501945080840160005b83811015613ff757815187529582019590820190600101613fdb565b509495945050505050565b600081518084526020808501945080840160005b83811015613ff757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614016565b85815260a06020820152600061406160a0830187613fc7565b73ffffffffffffffffffffffffffffffffffffffff808716604085015283820360608501526140908287614002565b9250808516608085015250509695505050505050565b815173ffffffffffffffffffffffffffffffffffffffff90811682526020808401518216908301526040808401519182169083015261012082019050606083015160608301526080830151608083015260a083015160a083015260c083015161411b60c084018267ffffffffffffffff169052565b5060e083015161413760e084018267ffffffffffffffff169052565b506101009283015163ffffffff16919092015290565b600067ffffffffffffffff808316818516808303821115613e1b57613e1b613da8565b60008282101561418257614182613da8565b500390565b6000821982111561419a5761419a613da8565b500190565b6020815281516020820152602082015160408201526000604083015160c060608401526141cf60e0840182613fc7565b905063ffffffff606085015116608084015273ffffffffffffffffffffffffffffffffffffffff60808501511660a084015260a08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c085015261243c8282614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826142785761427861423a565b500490565b60008261428c5761428c61423a565b500690565b6000602082840312156142a357600080fd5b81516128b8816137a8565b600067ffffffffffffffff83811690831681811015613df457613df4613da8565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430757614307613da8565b500290565b6000825161431e8184602087016139ee565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220355f32bdb028a28cbe50e81ac06a0ec2427ffb0f4e0b67010c2cd12bb9b1455664736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/LpTokenFactory.json b/deployments/rinkeby/LpTokenFactory.json index 42678ffd..1bd08ca1 100644 --- a/deployments/rinkeby/LpTokenFactory.json +++ b/deployments/rinkeby/LpTokenFactory.json @@ -40,7 +40,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _append(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _append(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _append(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x3af40092646f132fcdba4c42b51359abcd3797e5084fad627dd27ba47e0ca9c9\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"createLpToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"createLpToken(address)\":{\"params\":{\"l1Token\":\"L1 token to name in LP token name.\"},\"returns\":{\"_0\":\"address of new LP token.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"createLpToken(address)\":{\"notice\":\"Deploys new LP token for L1 token. Sets caller as minter and burner of token.\"}},\"notice\":\"Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the intended client of this contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/LpTokenFactory.sol\":\"LpTokenFactory\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = _allowances[owner][spender];\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n }\\n _balances[to] += amount;\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n _balances[account] += amount;\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n }\\n _totalSupply -= amount;\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0xdadd41acb749920eccf40aeaa8d291adf9751399a7343561bad13e7a8d99be0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"./MultiRole.sol\\\";\\nimport \\\"../interfaces/ExpandedIERC20.sol\\\";\\n\\n/**\\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\\n * be the owner who is capable of adding new roles.\\n */\\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\\n enum Roles {\\n // Can set the minter and burner.\\n Owner,\\n // Addresses that can mint new tokens.\\n Minter,\\n // Addresses that can burn tokens that address owns.\\n Burner\\n }\\n\\n uint8 _decimals;\\n\\n /**\\n * @notice Constructs the ExpandedERC20.\\n * @param _tokenName The name which describes the new token.\\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\\n * @param _tokenDecimals The number of decimals to define token precision.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _tokenSymbol,\\n uint8 _tokenDecimals\\n ) ERC20(_tokenName, _tokenSymbol) {\\n _decimals = _tokenDecimals;\\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\\n }\\n\\n function decimals() public view virtual override(ERC20) returns (uint8) {\\n return _decimals;\\n }\\n\\n /**\\n * @dev Mints `value` tokens to `recipient`, returning true on success.\\n * @param recipient address to mint to.\\n * @param value amount of tokens to mint.\\n * @return True if the mint succeeded, or False.\\n */\\n function mint(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Minter))\\n returns (bool)\\n {\\n _mint(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `msg.sender`.\\n * @param value amount of tokens to burn.\\n */\\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\\n _burn(msg.sender, value);\\n }\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n * @return True if the burn succeeded, or False.\\n */\\n function burnFrom(address recipient, uint256 value)\\n external\\n override\\n onlyRoleHolder(uint256(Roles.Burner))\\n returns (bool)\\n {\\n _burn(recipient, value);\\n return true;\\n }\\n\\n /**\\n * @notice Add Minter role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Minter role is added.\\n */\\n function addMinter(address account) external virtual override {\\n addMember(uint256(Roles.Minter), account);\\n }\\n\\n /**\\n * @notice Add Burner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The address to which the Burner role is added.\\n */\\n function addBurner(address account) external virtual override {\\n addMember(uint256(Roles.Burner), account);\\n }\\n\\n /**\\n * @notice Reset Owner role to account.\\n * @dev The caller must have the Owner role.\\n * @param account The new holder of the Owner role.\\n */\\n function resetOwner(address account) external virtual override {\\n resetMember(uint256(Roles.Owner), account);\\n }\\n}\\n\",\"keccak256\":\"0x8201459d3f78a1f97da7c421f2fbb859924d4facfc5fc235ba65d85bf12b2229\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/implementation/MultiRole.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nlibrary Exclusive {\\n struct RoleMembership {\\n address member;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.member == memberToCheck;\\n }\\n\\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\\n require(newMember != address(0x0), \\\"Cannot set an exclusive role to 0x0\\\");\\n roleMembership.member = newMember;\\n }\\n\\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\\n return roleMembership.member;\\n }\\n\\n function init(RoleMembership storage roleMembership, address initialMember) internal {\\n resetMember(roleMembership, initialMember);\\n }\\n}\\n\\nlibrary Shared {\\n struct RoleMembership {\\n mapping(address => bool) members;\\n }\\n\\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\\n return roleMembership.members[memberToCheck];\\n }\\n\\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\\n require(memberToAdd != address(0x0), \\\"Cannot add 0x0 to a shared role\\\");\\n roleMembership.members[memberToAdd] = true;\\n }\\n\\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\\n roleMembership.members[memberToRemove] = false;\\n }\\n\\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\\n for (uint256 i = 0; i < initialMembers.length; i++) {\\n addMember(roleMembership, initialMembers[i]);\\n }\\n }\\n}\\n\\n/**\\n * @title Base class to manage permissions for the derived class.\\n */\\nabstract contract MultiRole {\\n using Exclusive for Exclusive.RoleMembership;\\n using Shared for Shared.RoleMembership;\\n\\n enum RoleType { Invalid, Exclusive, Shared }\\n\\n struct Role {\\n uint256 managingRole;\\n RoleType roleType;\\n Exclusive.RoleMembership exclusiveRoleMembership;\\n Shared.RoleMembership sharedRoleMembership;\\n }\\n\\n mapping(uint256 => Role) private roles;\\n\\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\\n\\n /**\\n * @notice Reverts unless the caller is a member of the specified roleId.\\n */\\n modifier onlyRoleHolder(uint256 roleId) {\\n require(holdsRole(roleId, msg.sender), \\\"Sender does not hold required role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\\n */\\n modifier onlyRoleManager(uint256 roleId) {\\n require(holdsRole(roles[roleId].managingRole, msg.sender), \\\"Can only be called by a role manager\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\\n */\\n modifier onlyExclusive(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Exclusive, \\\"Must be called on an initialized Exclusive role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\\n */\\n modifier onlyShared(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Shared, \\\"Must be called on an initialized Shared role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Whether `memberToCheck` is a member of roleId.\\n * @dev Reverts if roleId does not correspond to an initialized role.\\n * @param roleId the Role to check.\\n * @param memberToCheck the address to check.\\n * @return True if `memberToCheck` is a member of `roleId`.\\n */\\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\\n Role storage role = roles[roleId];\\n if (role.roleType == RoleType.Exclusive) {\\n return role.exclusiveRoleMembership.isMember(memberToCheck);\\n } else if (role.roleType == RoleType.Shared) {\\n return role.sharedRoleMembership.isMember(memberToCheck);\\n }\\n revert(\\\"Invalid roleId\\\");\\n }\\n\\n /**\\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\\n * initialized, ExclusiveRole.\\n * @param roleId the ExclusiveRole membership to modify.\\n * @param newMember the new ExclusiveRole member.\\n */\\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Gets the current holder of the exclusive role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\\n * @param roleId the ExclusiveRole membership to check.\\n * @return the address of the current ExclusiveRole member.\\n */\\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\\n return roles[roleId].exclusiveRoleMembership.getMember();\\n }\\n\\n /**\\n * @notice Adds `newMember` to the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param newMember the new SharedRole member.\\n */\\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.addMember(newMember);\\n emit AddedSharedMember(roleId, newMember, msg.sender);\\n }\\n\\n /**\\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\\n * managing role for `roleId`.\\n * @param roleId the SharedRole membership to modify.\\n * @param memberToRemove the current SharedRole member to remove.\\n */\\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\\n }\\n\\n /**\\n * @notice Removes caller from the role, `roleId`.\\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\\n * initialized, SharedRole.\\n * @param roleId the SharedRole membership to modify.\\n */\\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is not initialized.\\n */\\n modifier onlyValidRole(uint256 roleId) {\\n require(roles[roleId].roleType != RoleType.Invalid, \\\"Attempted to use an invalid roleId\\\");\\n _;\\n }\\n\\n /**\\n * @notice Reverts if `roleId` is initialized.\\n */\\n modifier onlyInvalidRole(uint256 roleId) {\\n require(roles[roleId].roleType == RoleType.Invalid, \\\"Cannot use a pre-existing role\\\");\\n _;\\n }\\n\\n /**\\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMembers` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createSharedRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address[] memory initialMembers\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Shared;\\n role.managingRole = managingRoleId;\\n role.sharedRoleMembership.init(initialMembers);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage a shared role\\\"\\n );\\n }\\n\\n /**\\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\\n * `initialMember` will be immediately added to the role.\\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\\n * initialized.\\n */\\n function _createExclusiveRole(\\n uint256 roleId,\\n uint256 managingRoleId,\\n address initialMember\\n ) internal onlyInvalidRole(roleId) {\\n Role storage role = roles[roleId];\\n role.roleType = RoleType.Exclusive;\\n role.managingRole = managingRoleId;\\n role.exclusiveRoleMembership.init(initialMember);\\n require(\\n roles[managingRoleId].roleType != RoleType.Invalid,\\n \\\"Attempted to use an invalid role to manage an exclusive role\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x134c5a2f847832705be631f2b4eb2a3e23a91a2f0e63560abb481e85eeebfae6\",\"license\":\"AGPL-3.0-only\"},\"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title ERC20 interface that includes burn and mint methods.\\n */\\nabstract contract ExpandedIERC20 is IERC20 {\\n /**\\n * @notice Burns a specific amount of the caller's tokens.\\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\\n */\\n function burn(uint256 value) external virtual;\\n\\n /**\\n * @dev Burns `value` tokens owned by `recipient`.\\n * @param recipient address to burn tokens from.\\n * @param value amount of tokens to burn.\\n */\\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\\n\\n /**\\n * @notice Mints tokens and adds them to the balance of the `to` address.\\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\\n */\\n function mint(address to, uint256 value) external virtual returns (bool);\\n\\n function addMinter(address account) external virtual;\\n\\n function addBurner(address account) external virtual;\\n\\n function resetOwner(address account) external virtual;\\n}\\n\",\"keccak256\":\"0xb8252039cba45f1c19cd677f150a9823a5d6e1845cad90e3041d97c96f273c26\",\"license\":\"AGPL-3.0-only\"},\"contracts/LpTokenFactory.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./interfaces/LpTokenFactoryInterface.sol\\\";\\n\\nimport \\\"@uma/core/contracts/common/implementation/ExpandedERC20.sol\\\";\\n\\n/**\\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\\n * intended client of this contract.\\n */\\ncontract LpTokenFactory is LpTokenFactoryInterface {\\n /**\\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\\n * @param l1Token L1 token to name in LP token name.\\n * @return address of new LP token.\\n */\\n function createLpToken(address l1Token) public returns (address) {\\n ExpandedERC20 lpToken = new ExpandedERC20(\\n _append(\\\"Across V2 \\\", IERC20Metadata(l1Token).name(), \\\" LP Token\\\"), // LP Token Name\\n _append(\\\"Av2-\\\", IERC20Metadata(l1Token).symbol(), \\\"-LP\\\"), // LP Token Symbol\\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\\n );\\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\\n\\n return address(lpToken);\\n }\\n\\n function _append(\\n string memory a,\\n string memory b,\\n string memory c\\n ) internal pure returns (string memory) {\\n return string(abi.encodePacked(a, b, c));\\n }\\n}\\n\",\"keccak256\":\"0x3af40092646f132fcdba4c42b51359abcd3797e5084fad627dd27ba47e0ca9c9\",\"license\":\"GPL-3.0-only\"},\"contracts/interfaces/LpTokenFactoryInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface LpTokenFactoryInterface {\\n function createLpToken(address l1Token) external returns (address);\\n}\\n\",\"keccak256\":\"0x9cf1d6df25bb1bdf34db2473f3caaa4264b628ae2fc0f0a5a0256fd41214b47d\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b50612d78806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212209d0b7b3b71c235b34e79d5b72791522522cbfce906136557bf267400633999a264736f6c634300080d0033", "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063fc2f1b6e1462000033575b600080fd5b6200004a6200004436600462000502565b62000073565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b600080620001806040518060400160405280600a81526020017f4163726f737320563220000000000000000000000000000000000000000000008152508473ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620000fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620001449190810190620005a3565b6040518060400160405280600981526020017f204c5020546f6b656e0000000000000000000000000000000000000000000000815250620004c3565b6200028a6040518060400160405280600481526020017f4176322d000000000000000000000000000000000000000000000000000000008152508573ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000206573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200024e9190810190620005a3565b6040518060400160405280600381526020017f2d4c500000000000000000000000000000000000000000000000000000000000815250620004c3565b8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fc91906200067a565b6040516200030a90620004f4565b6200031893929190620006eb565b604051809103906000f08015801562000335573d6000803e3d6000fd5b506040517f983b2d5600000000000000000000000000000000000000000000000000000000815233600482015290915073ffffffffffffffffffffffffffffffffffffffff82169063983b2d5690602401600060405180830381600087803b158015620003a157600080fd5b505af1158015620003b6573d6000803e3d6000fd5b50506040517ff44637ba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8416925063f44637ba9150602401600060405180830381600087803b1580156200042257600080fd5b505af115801562000437573d6000803e3d6000fd5b50506040517f73cc802a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff841692506373cc802a9150602401600060405180830381600087803b158015620004a357600080fd5b505af1158015620004b8573d6000803e3d6000fd5b509295945050505050565b6060838383604051602001620004dc9392919062000728565b60405160208183030381529060405290509392505050565b6125d1806200077283390190565b6000602082840312156200051557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146200053a57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156200058d57818101518382015260200162000573565b838111156200059d576000848401525b50505050565b600060208284031215620005b657600080fd5b815167ffffffffffffffff80821115620005cf57600080fd5b818401915084601f830112620005e457600080fd5b815181811115620005f957620005f962000541565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171562000642576200064262000541565b816040528281528760208487010111156200065c57600080fd5b6200066f83602083016020880162000570565b979650505050505050565b6000602082840312156200068d57600080fd5b815160ff811681146200053a57600080fd5b60008151808452620006b981602086016020860162000570565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6060815260006200070060608301866200069f565b82810360208401526200071481866200069f565b91505060ff83166040830152949350505050565b600084516200073c81846020890162000570565b8451908301906200075281836020890162000570565b84519101906200076781836020880162000570565b019594505050505056fe60806040523480156200001157600080fd5b50604051620025d1380380620025d1833981016040819052620000349162000621565b8251839083906200004d906003906020850190620004ae565b50805162000063906004906020840190620004ae565b50506006805460ff191660ff8416179055506200008360008033620000b5565b620000a060015b6040805160008082526020820190925262000205565b620000ac60026200008a565b50505062000736565b826000808281526005602052604090206001015460ff166002811115620000e057620000e0620006a6565b14620001335760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064015b60405180910390fd5b60008481526005602052604090206001808201805460ff1916828002179055508381556200017160028201846200034b602090811b6200111517901c565b60008481526005602052604081206001015460ff1660028111156200019a576200019a620006a6565b03620001fe5760405162461bcd60e51b815260206004820152603c6024820152600080516020620025b183398151915260448201527f20746f206d616e61676520616e206578636c757369766520726f6c650000000060648201526084016200012a565b5050505050565b826000808281526005602052604090206001015460ff166002811115620002305762000230620006a6565b146200027f5760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f74207573652061207072652d6578697374696e6720726f6c65000060448201526064016200012a565b600084815260056020908152604090912060018101805460ff1916600217905584815590620002be90600383019085906200111f6200035b821b17901c565b60008481526005602052604081206001015460ff166002811115620002e757620002e7620006a6565b03620001fe5760405162461bcd60e51b81526020600482015260386024820152600080516020620025b183398151915260448201527f20746f206d616e61676520612073686172656420726f6c65000000000000000060648201526084016200012a565b620003578282620003b0565b5050565b60005b8151811015620003ab576200039683838381518110620003825762000382620006bc565b60200260200101516200043160201b60201c565b80620003a281620006d2565b9150506200035e565b505050565b6001600160a01b038116620004145760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201526203078360ec1b60648201526084016200012a565b81546001600160a01b0319166001600160a01b0391909116179055565b6001600160a01b038116620004895760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c650060448201526064016200012a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b828054620004bc90620006fa565b90600052602060002090601f016020900481019282620004e057600085556200052b565b82601f10620004fb57805160ff19168380011785556200052b565b828001600101855582156200052b579182015b828111156200052b5782518255916020019190600101906200050e565b50620005399291506200053d565b5090565b5b808211156200053957600081556001016200053e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200057c57600080fd5b81516001600160401b038082111562000599576200059962000554565b604051601f8301601f19908116603f01168101908282118183101715620005c457620005c462000554565b81604052838152602092508683858801011115620005e157600080fd5b600091505b83821015620006055785820183015181830184015290820190620005e6565b83821115620006175760008385830101525b9695505050505050565b6000806000606084860312156200063757600080fd5b83516001600160401b03808211156200064f57600080fd5b6200065d878388016200056a565b945060208601519150808211156200067457600080fd5b5062000683868287016200056a565b925050604084015160ff811681146200069b57600080fd5b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060018201620006f357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200070f57607f821691505b6020821081036200073057634e487b7160e01b600052602260045260246000fd5b50919050565b611e6b80620007466000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806374d0a676116100e3578063a9059cbb1161008c578063d97c05be11610066578063d97c05be14610369578063dd62ed3e1461037c578063f44637ba146103c257600080fd5b8063a9059cbb1461030b578063aaa14ca31461031e578063ab3545e51461033157600080fd5b806395d89b41116100bd57806395d89b41146102dd578063983b2d56146102e5578063a457c2d7146102f857600080fd5b806374d0a676146102a457806379cc6790146102b75780637cdc1cb9146102ca57600080fd5b806339509351116101455780636be7658b1161011f5780636be7658b1461024857806370a082311461025b57806373cc802a1461029157600080fd5b8063395093511461020d57806340c10f191461022057806342966c681461023357600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a6103d5565b6040516101a79190611b61565b60405180910390f35b6101c36101be366004611bfd565b610467565b60405190151581526020016101a7565b6002545b6040519081526020016101a7565b6101c36101f3366004611c27565b610481565b60065460405160ff90911681526020016101a7565b6101c361021b366004611bfd565b6104a5565b6101c361022e366004611bfd565b6104f1565b610246610241366004611c63565b61059a565b005b610246610256366004611c7c565b610640565b6101d7610269366004611ca8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024661029f366004611ca8565b610827565b6102466102b2366004611c7c565b610835565b6101c36102c5366004611bfd565b6109f7565b6101c36102d8366004611c7c565b610a9b565b61019a610ba3565b6102466102f3366004611ca8565b610bb2565b6101c3610306366004611bfd565b610bbe565b6101c3610319366004611bfd565b610c8f565b61024661032c366004611c63565b610c9d565b61034461033f366004611c63565b610e60565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b610246610377366004611c7c565b610f49565b6101d761038a366004611cca565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6102466103d0366004611ca8565b61110b565b6060600380546103e490611cf4565b80601f016020809104026020016040519081016040528092919081815260200182805461041090611cf4565b801561045d5780601f106104325761010080835404028352916020019161045d565b820191906000526020600020905b81548152906001019060200180831161044057829003601f168201915b5050505050905090565b600033610475818585611165565b60019150505b92915050565b60003361048f858285611318565b61049a8585856113ef565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061047590829086906104ec908790611d70565b611165565b600060016104ff8133610a9b565b610590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c6500000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61047584846116a2565b60026105a68133610a9b565b610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61063c33836117c2565b5050565b81600260008281526005602052604090206001015460ff16600281111561066957610669611d88565b146106f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906107119033610a9b565b61079c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b600084815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552600390910190925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af9190a450505050565b610832600082610f49565b50565b81600260008281526005602052604090206001015460ff16600281111561085e5761085e611d88565b146108eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b60008381526005602052604090205483906109069033610a9b565b610991576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206109ac90600301846119af565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f63502af7324ff6db91ab38f8236a648727d9385ea6c782073dd4882d8a61a48f90600090a450505050565b60006002610a058133610a9b565b610a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b61047584846117c2565b600082815260056020526040812060018082015460ff166002811115610ac357610ac3611d88565b03610af157600281015473ffffffffffffffffffffffffffffffffffffffff8481169116145b91505061047b565b6002600182015460ff166002811115610b0c57610b0c611d88565b03610b415773ffffffffffffffffffffffffffffffffffffffff8316600090815260038201602052604090205460ff16610ae9565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420726f6c6549640000000000000000000000000000000000006044820152606401610587565b6060600480546103e490611cf4565b61083260015b82610835565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610c82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610587565b61049a8286868403611165565b6000336104758185856113ef565b80600260008281526005602052604090206001015460ff166002811115610cc657610cc6611d88565b14610d53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f2053686172656420726f6c6500000000000000000000000000000000000000006064820152608401610587565b81610d5e8133610a9b565b610dea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f53656e64657220646f6573206e6f7420686f6c6420726571756972656420726f60448201527f6c650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b6000838152600560209081526040808320338452600301909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513390819085907feb3e33034c392e69263b04ec0fa376dc12784a41b6676c7f31b936cbc0fbb5af90600090a4505050565b600081600160008281526005602052604090206001015460ff166002811115610e8b57610e8b611d88565b14610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b60008381526005602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1691505b50919050565b81600160008281526005602052604090206001015460ff166002811115610f7257610f72611d88565b14610fff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d7573742062652063616c6c6564206f6e20616e20696e697469616c697a656460448201527f204578636c757369766520726f6c6500000000000000000000000000000000006064820152608401610587565b600083815260056020526040902054839061101a9033610a9b565b6110a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e206f6e6c792062652063616c6c6564206279206120726f6c65206d616e60448201527f61676572000000000000000000000000000000000000000000000000000000006064820152608401610587565b60008481526005602052604090206110c09060020184611a7c565b604051339073ffffffffffffffffffffffffffffffffffffffff85169086907f3b855c56b409b671c7112789d022675eb639d0bcb8896f1b6197c132f799e74690600090a450505050565b6108326002610bb8565b61063c8282611a7c565b60005b81518110156111605761114e8383838151811061114157611141611db7565b60200260200101516119af565b8061115881611de6565b915050611122565b505050565b73ffffffffffffffffffffffffffffffffffffffff8316611207576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166112aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113e957818110156113dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610587565b6113e98484848403611165565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8216611535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054818110156115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061162f908490611d70565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161169591815260200190565b60405180910390a36113e9565b73ffffffffffffffffffffffffffffffffffffffff821661171f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610587565b80600260008282546117319190611d70565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061176b908490611d70565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216611865576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561191b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610587565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290611957908490611e1e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e6e6f74206164642030783020746f20612073686172656420726f6c65006044820152606401610587565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020919091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8116611b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f43616e6e6f742073657420616e206578636c757369766520726f6c6520746f2060448201527f30783000000000000000000000000000000000000000000000000000000000006064820152608401610587565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b600060208083528351808285015260005b81811015611b8e57858101830151858201604001528201611b72565b81811115611ba0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bf857600080fd5b919050565b60008060408385031215611c1057600080fd5b611c1983611bd4565b946020939093013593505050565b600080600060608486031215611c3c57600080fd5b611c4584611bd4565b9250611c5360208501611bd4565b9150604084013590509250925092565b600060208284031215611c7557600080fd5b5035919050565b60008060408385031215611c8f57600080fd5b82359150611c9f60208401611bd4565b90509250929050565b600060208284031215611cba57600080fd5b611cc382611bd4565b9392505050565b60008060408385031215611cdd57600080fd5b611ce683611bd4565b9150611c9f60208401611bd4565b600181811c90821680611d0857607f821691505b602082108103610f43577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8357611d83611d41565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e1757611e17611d41565b5060010190565b600082821015611e3057611e30611d41565b50039056fea2646970667358221220af62dd4c842a6ec357c4de2464fc459ad78dbb38819fa288eb99f4a3a869cfcb64736f6c634300080d0033417474656d7074656420746f2075736520616e20696e76616c696420726f6c65a26469706673582212209d0b7b3b71c235b34e79d5b72791522522cbfce906136557bf267400633999a264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Optimism_Adapter.json b/deployments/rinkeby/Optimism_Adapter.json index fe050961..6f432d09 100644 --- a/deployments/rinkeby/Optimism_Adapter.json +++ b/deployments/rinkeby/Optimism_Adapter.json @@ -246,7 +246,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"OVM_XCHAIN: messenger contract unauthenticated\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0xb9a90934f8e09dd581cb65fa9d2f7904bfcb0dfe86f45a8b31d0b3037a1facd3\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 5_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Optimism.\\n * @param target Contract on Optimism that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Optimism.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d38de11bc73db08f7406261d9b64b2985faa06cbd48aa8cc28042efd284e4d9\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"_l1StandardBridge\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dai\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"daiOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"contract IL1StandardBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2GasLimit\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snx\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"snxOptimismBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_crossDomainMessenger\":\"XDomainMessenger Optimism system contract.\",\"_l1StandardBridge\":\"Standard bridge contract.\",\"_l1Weth\":\"WETH address on L1.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Optimism that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Optimism.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Optimism.\"}},\"notice\":\"Contract containing logic to send messages from L1 to Optimism.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Optimism_Adapter.sol\":\"Optimism_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts/L1/messaging/IL1ERC20Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title IL1ERC20Bridge\\n */\\ninterface IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n\\n event ERC20DepositInitiated(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ERC20WithdrawalFinalized(\\n address indexed _l1Token,\\n address indexed _l2Token,\\n address indexed _from,\\n address _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev get the address of the corresponding L2 bridge contract.\\n * @return Address of the corresponding L2 bridge contract.\\n */\\n function l2TokenBridge() external returns (address);\\n\\n /**\\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _amount Amount of the ERC20 to deposit\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20(\\n address _l1Token,\\n address _l2Token,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n * @param _l1Token Address of the L1 ERC20 we are depositing\\n * @param _l2Token Address of the L1 respective L2 ERC20\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositERC20To(\\n address _l1Token,\\n address _l2Token,\\n address _to,\\n uint256 _amount,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ERC20 token.\\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\\n *\\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\\n * @param _l2Token Address of L2 token where withdrawal was initiated.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Data provided by the sender on L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeERC20Withdrawal(\\n address _l1Token,\\n address _l2Token,\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x69f831896dcbb6bef4f2d6c8be6cd1bf352f5910074d3ce973b9f8e0a4f4c1dd\",\"license\":\"MIT\"},\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\nimport \\\"./IL1ERC20Bridge.sol\\\";\\n\\n/**\\n * @title IL1StandardBridge\\n */\\ninterface IL1StandardBridge is IL1ERC20Bridge {\\n /**********\\n * Events *\\n **********/\\n event ETHDepositInitiated(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n event ETHWithdrawalFinalized(\\n address indexed _from,\\n address indexed _to,\\n uint256 _amount,\\n bytes _data\\n );\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\\n\\n /**\\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\\n * @param _to L2 address to credit the withdrawal to.\\n * @param _l2Gas Gas limit required to complete the deposit on L2.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function depositETHTo(\\n address _to,\\n uint32 _l2Gas,\\n bytes calldata _data\\n ) external payable;\\n\\n /*************************\\n * Cross-chain Functions *\\n *************************/\\n\\n /**\\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\\n * before the withdrawal is finalized.\\n * @param _from L2 address initiating the transfer.\\n * @param _to L1 address to credit the withdrawal to.\\n * @param _amount Amount of the ERC20 to deposit.\\n * @param _data Optional data to forward to L2. This data is provided\\n * solely as a convenience for external contracts. Aside from enforcing a maximum\\n * length, these contracts provide no guarantees about its content.\\n */\\n function finalizeETHWithdrawal(\\n address _from,\\n address _to,\\n uint256 _amount,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x3d511f1bcea86aa88a9c41798926ea75b5b3f455c0377e63223a123a9e714ddc\",\"license\":\"MIT\"},\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/**\\n * @title ICrossDomainMessenger\\n */\\ninterface ICrossDomainMessenger {\\n /**********\\n * Events *\\n **********/\\n\\n event SentMessage(\\n address indexed target,\\n address sender,\\n bytes message,\\n uint256 messageNonce,\\n uint256 gasLimit\\n );\\n event RelayedMessage(bytes32 indexed msgHash);\\n event FailedRelayedMessage(bytes32 indexed msgHash);\\n\\n /*************\\n * Variables *\\n *************/\\n\\n function xDomainMessageSender() external view returns (address);\\n\\n /********************\\n * Public Functions *\\n ********************/\\n\\n /**\\n * Sends a cross domain message to the target messenger.\\n * @param _target Target contract address.\\n * @param _message Message to send to the target.\\n * @param _gasLimit Gas limit for the provided message.\\n */\\n function sendMessage(\\n address _target,\\n bytes calldata _message,\\n uint32 _gasLimit\\n ) external;\\n}\\n\",\"keccak256\":\"0x8f29ae23021345a20ccac7b5edb3fc38268aef943b65adc8a32e74b80bf1833a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/CrossDomainEnabled.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >0.5.0 <0.9.0;\\n\\n/* Interface Imports */\\nimport { ICrossDomainMessenger } from \\\"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\\\";\\n\\n/**\\n * @title CrossDomainEnabled\\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\\n */\\ncontract CrossDomainEnabled {\\n // Messenger contract used to send and recieve messages from the other domain.\\n address public immutable messenger;\\n\\n /**\\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\\n */\\n constructor(address _messenger) {\\n messenger = _messenger;\\n }\\n\\n /**\\n * Enforces that the modified function is only callable by a specific cross-domain account.\\n * @param _sourceDomainAccount The only account on the originating domain which is\\n * authenticated to call this function.\\n */\\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\\n require(msg.sender == address(getCrossDomainMessenger()), \\\"OVM_XCHAIN: messenger contract unauthenticated\\\");\\n\\n require(\\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\\n \\\"OVM_XCHAIN: wrong sender of cross-domain message\\\"\\n );\\n\\n _;\\n }\\n\\n /**\\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\\n * needs to override.\\n * @return The address of the cross-domain messenger contract which should be used.\\n */\\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\\n return ICrossDomainMessenger(messenger);\\n }\\n\\n /**\\n * Sends a message to an account on another domain\\n * @param _crossDomainTarget The intended recipient on the destination domain\\n * @param _message The data to send to the target (usually calldata to a function with\\n * onlyFromCrossDomainAccount())\\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\\n */\\n function sendCrossDomainMessage(\\n address _crossDomainTarget,\\n uint32 _gasLimit,\\n bytes memory _message\\n ) internal {\\n // slither-disable-next-line reentrancy-events, reentrancy-benign\\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\\n }\\n}\\n\",\"keccak256\":\"0xb9a90934f8e09dd581cb65fa9d2f7904bfcb0dfe86f45a8b31d0b3037a1facd3\",\"license\":\"MIT\"},\"contracts/chain-adapters/Optimism_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\\n// this contract's state variables to be `immutable` because of the delegateCall call.\\nimport \\\"./CrossDomainEnabled.sol\\\";\\nimport \\\"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @notice Contract containing logic to send messages from L1 to Optimism.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\\n using SafeERC20 for IERC20;\\n uint32 public immutable l2GasLimit = 5_000_000;\\n\\n WETH9 public immutable l1Weth;\\n\\n IL1StandardBridge public immutable l1StandardBridge;\\n\\n // Optimism has the ability to support \\\"custom\\\" bridges. These bridges are not supported by the canonical bridge\\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _l1Weth WETH address on L1.\\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\\n * @param _l1StandardBridge Standard bridge contract.\\n */\\n constructor(\\n WETH9 _l1Weth,\\n address _crossDomainMessenger,\\n IL1StandardBridge _l1StandardBridge\\n ) CrossDomainEnabled(_crossDomainMessenger) {\\n l1Weth = _l1Weth;\\n l1StandardBridge = _l1StandardBridge;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Optimism.\\n * @param target Contract on Optimism that will receive message.\\n * @param message Data to send to target.\\n */\\n function relayMessage(address target, bytes memory message) external payable override {\\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Optimism.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \\\"\\\");\\n } else {\\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\\n\\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\\n\\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \\\"\\\");\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d38de11bc73db08f7406261d9b64b2985faa06cbd48aa8cc28042efd284e4d9\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x610180604052624c4b4060a052736b175474e89094c44da98b954eedeac495271d0f610100527310e6593cdda8c58a1d0f14c5164b376352a55f2f6101205273c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6101405273cd9d4988c0ae61887b075ba77f08cbfad2b650686101605234801561007c57600080fd5b5060405161117138038061117183398101604081905261009b916100d0565b6001600160a01b0391821660805291811660c0521660e05261011d565b6001600160a01b03811681146100cd57600080fd5b50565b6000806000606084860312156100e557600080fd5b83516100f0816100b8565b6020850151909350610101816100b8565b6040850151909250610112816100b8565b809150509250925092565b60805160a05160c05160e05161010051610120516101405161016051610f9c6101d56000396000818161015a015261056c01526000818161026701526105180152600081816101d701526104f601526000818161029b01526104ca01526000818160c80152818161042d0152610494015260008181610126015281816102bf015261033f01526000818161020b015281816103f80152818161060e01526106ec01526000818161018e01526108c60152610f9c6000f3fe6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c77565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610cf3565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff8616828561074e565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610711827f000000000000000000000000000000000000000000000000000000000000000083610889565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610742929190610e49565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190610e78565b6107f39190610e91565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610883908590610936565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b906108ff90869085908790600401610ed0565b600060405180830381600087803b15801561091957600080fd5b505af115801561092d573d6000803e3d6000fd5b50505050505050565b6000610998826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4c9092919063ffffffff16565b805190915015610a4757808060200190518101906109b69190610f15565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a5b8484600085610a65565b90505b9392505050565b606082471015610af7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3e565b73ffffffffffffffffffffffffffffffffffffffff85163b610b75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b9e9190610f37565b60006040518083038185875af1925050503d8060008114610bdb576040519150601f19603f3d011682016040523d82523d6000602084013e610be0565b606091505b5091509150610bf0828286610bfb565b979650505050505050565b60608315610c0a575081610a5e565b825115610c1a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e9190610f53565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7257600080fd5b919050565b60008060008060808587031215610c8d57600080fd5b610c9685610c4e565b9350610ca460208601610c4e565b925060408501359150610cb960608601610c4e565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0657600080fd5b610d0f83610c4e565b9150602083013567ffffffffffffffff80821115610d2c57600080fd5b818501915085601f830112610d4057600080fd5b813581811115610d5257610d52610cc4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9857610d98610cc4565b81604052828152886020848701011115610db157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610dee578181015183820152602001610dd6565b838111156108835750506000910152565b60008151808452610e17816020860160208601610dd3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5b6040830184610dff565b600060208284031215610e8a57600080fd5b5051919050565b60008219821115610ecb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000610eff6060830185610dff565b905063ffffffff83166040830152949350505050565b600060208284031215610f2757600080fd5b81518015158114610a5e57600080fd5b60008251610f49818460208701610dd3565b9190910192915050565b602081526000610a5e6020830184610dff56fea2646970667358221220b439c41917b515109464c40d4dc8343a6f6e68157bca87353f5213176038c50a64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100b15760003560e01c8063b708886d11610069578063e6eb8ade1161004e578063e6eb8ade14610242578063e7d2799814610255578063f4b9fa751461028957600080fd5b8063b708886d146101c5578063cf6e65b7146101f957600080fd5b806328f7c66b1161009a57806328f7c66b146101485780633cb747bf1461017c57806352c8c75c146101b057600080fd5b8063078f29cf146100b6578063146bf4b114610114575b600080fd5b3480156100c257600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012057600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561015457600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018857600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be366004610c77565b6102bd565b005b3480156101d157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020557600080fd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161010b565b6101c3610250366004610cf3565b6106e6565b34801561026157600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561029557600080fd5b506100ea7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610492576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561039857600080fd5b505af11580156103ac573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602483015260606044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915084906084016000604051808303818588803b15801561047457600080fd5b505af1158015610488573d6000803e3d6000fd5b5050505050610681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169086160361051657507f00000000000000000000000000000000000000000000000000000000000000005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361058c57507f00000000000000000000000000000000000000000000000000000000000000005b6105ad73ffffffffffffffffffffffffffffffffffffffff8616828561074e565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015283811660448301526064820185905263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016608483015260c060a4830152600060c483015282169063838b25209060e401600060405180830381600087803b15801561066757600080fd5b505af115801561067b573d6000803e3d6000fd5b50505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b610711827f000000000000000000000000000000000000000000000000000000000000000083610889565b7f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610742929190610e49565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190610e78565b6107f39190610e91565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052909150610883908590610936565b50505050565b6040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b906108ff90869085908790600401610ed0565b600060405180830381600087803b15801561091957600080fd5b505af115801561092d573d6000803e3d6000fd5b50505050505050565b6000610998826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a4c9092919063ffffffff16565b805190915015610a4757808060200190518101906109b69190610f15565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610a5b8484600085610a65565b90505b9392505050565b606082471015610af7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3e565b73ffffffffffffffffffffffffffffffffffffffff85163b610b75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b9e9190610f37565b60006040518083038185875af1925050503d8060008114610bdb576040519150601f19603f3d011682016040523d82523d6000602084013e610be0565b606091505b5091509150610bf0828286610bfb565b979650505050505050565b60608315610c0a575081610a5e565b825115610c1a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3e9190610f53565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7257600080fd5b919050565b60008060008060808587031215610c8d57600080fd5b610c9685610c4e565b9350610ca460208601610c4e565b925060408501359150610cb960608601610c4e565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610d0657600080fd5b610d0f83610c4e565b9150602083013567ffffffffffffffff80821115610d2c57600080fd5b818501915085601f830112610d4057600080fd5b813581811115610d5257610d52610cc4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610d9857610d98610cc4565b81604052828152886020848701011115610db157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610dee578181015183820152602001610dd6565b838111156108835750506000910152565b60008151808452610e17816020860160208601610dd3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a5b6040830184610dff565b600060208284031215610e8a57600080fd5b5051919050565b60008219821115610ecb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000610eff6060830185610dff565b905063ffffffff83166040830152949350505050565b600060208284031215610f2757600080fd5b81518015158114610a5e57600080fd5b60008251610f49818460208701610dd3565b9190910192915050565b602081526000610a5e6020830184610dff56fea2646970667358221220b439c41917b515109464c40d4dc8343a6f6e68157bca87353f5213176038c50a64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/PolygonTokenBridger.json b/deployments/rinkeby/PolygonTokenBridger.json index d2052b71..b560d73e 100644 --- a/deployments/rinkeby/PolygonTokenBridger.json +++ b/deployments/rinkeby/PolygonTokenBridger.json @@ -116,7 +116,7 @@ "args": ["0xa1b6DA4AaE90fA16F3A3338c8d1Dc70B4926FCa7", "0xc778417E063141139Fce010982780140Aa0cD5Ab"], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWrappedMatic\",\"type\":\"bool\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1Weth\":\"Ethereum WETH address.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256,bool)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"isWrappedMatic\":\"True if token is WMATIC.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256,bool)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\ninterface PolygonIERC20 is IERC20 {\\n function withdraw(uint256 amount) external;\\n}\\n\\ninterface MaticToken {\\n function withdraw(uint256 amount) external payable;\\n}\\n\\n/**\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\n * mechanism from normal create.\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\n * sender.\\n */\\ncontract PolygonTokenBridger is Lockable {\\n using SafeERC20 for PolygonIERC20;\\n using SafeERC20 for IERC20;\\n\\n // Gas token for Polygon.\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\n\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\n address public immutable destination;\\n\\n // WETH contract on Ethereum.\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs Token Bridger contract.\\n * @param _destination Where to send tokens to for this network.\\n * @param _l1Weth Ethereum WETH address.\\n */\\n constructor(address _destination, WETH9 _l1Weth) {\\n destination = _destination;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\n * @notice The caller of this function must approve this contract to spend amount of token.\\n * @param token Token to bridge.\\n * @param amount Amount to bridge.\\n * @param isWrappedMatic True if token is WMATIC.\\n */\\n function send(\\n PolygonIERC20 token,\\n uint256 amount,\\n bool isWrappedMatic\\n ) public nonReentrant {\\n token.safeTransferFrom(msg.sender, address(this), amount);\\n\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\n token.withdraw(amount);\\n\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\\n }\\n\\n /**\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\n * @param token Token to send to destination.\\n */\\n function retrieve(IERC20 token) public nonReentrant {\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\n }\\n\\n receive() external payable {\\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\\n }\\n}\\n\",\"keccak256\":\"0x79b3a0f440bf429abcb41d4d808892d0bd73e890334585f3ab1dd67a2bbe32cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_destination\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"destination\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maticToken\",\"outputs\":[{\"internalType\":\"contract MaticToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"retrieve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract PolygonIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isWrappedMatic\",\"type\":\"bool\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as it is created via create2. create2 is an alternative creation method that uses a different address determination mechanism from normal create. Normal create: address = hash(deployer_address, deployer_nonce) create2: address = hash(0xFF, sender, salt, bytecode) This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the sender.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_destination\":\"Where to send tokens to for this network.\",\"_l1Weth\":\"Ethereum WETH address.\"}},\"retrieve(address)\":{\"params\":{\"token\":\"Token to send to destination.\"}},\"send(address,uint256,bool)\":{\"params\":{\"amount\":\"Amount to bridge.\",\"isWrappedMatic\":\"True if token is WMATIC.\",\"token\":\"Token to bridge.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs Token Bridger contract.\"},\"retrieve(address)\":{\"notice\":\"Called by someone to send tokens to the destination, which should be set to the HubPool.\"},\"send(address,uint256,bool)\":{\"notice\":\"Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.The caller of this function must approve this contract to spend amount of token.\"}},\"notice\":\"Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/PolygonTokenBridger.sol\":\"PolygonTokenBridger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/Lockable.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\\n * by uma/contracts.\\n */\\ncontract Lockable {\\n bool internal _notEntered;\\n\\n constructor() {\\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\\n // refund coming into effect.\\n _notEntered = true;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\\n * prevent this from happening by making the nonReentrant function external, and making it call a private\\n * function that does the actual state modification.\\n */\\n modifier nonReentrant() {\\n _preEntranceCheck();\\n _preEntranceSet();\\n _;\\n _postEntranceReset();\\n }\\n\\n /**\\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\\n */\\n modifier nonReentrantView() {\\n _preEntranceCheck();\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\\n * contract, such as unwrapping WETH to ETH within the contract.\\n */\\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\\n return _notEntered;\\n }\\n\\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\\n // then call _postEntranceReset().\\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\\n function _preEntranceCheck() internal view {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_notEntered, \\\"ReentrancyGuard: reentrant call\\\");\\n }\\n\\n function _preEntranceSet() internal {\\n // Any calls to nonReentrant after this point will fail\\n _notEntered = false;\\n }\\n\\n function _postEntranceReset() internal {\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _notEntered = true;\\n }\\n}\\n\",\"keccak256\":\"0xef490be5cb859c97c6f600f3b0db0d50c6e18f334d3c74c6d9e693a260eaec3e\",\"license\":\"AGPL-3.0-only\"},\"contracts/PolygonTokenBridger.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"./Lockable.sol\\\";\\nimport \\\"./interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\\ninterface PolygonIERC20 is IERC20 {\\n function withdraw(uint256 amount) external;\\n}\\n\\ninterface MaticToken {\\n function withdraw(uint256 amount) external payable;\\n}\\n\\n/**\\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\\n * mechanism from normal create.\\n * Normal create: address = hash(deployer_address, deployer_nonce)\\n * create2: address = hash(0xFF, sender, salt, bytecode)\\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\\n * sender.\\n */\\ncontract PolygonTokenBridger is Lockable {\\n using SafeERC20 for PolygonIERC20;\\n using SafeERC20 for IERC20;\\n\\n // Gas token for Polygon.\\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\\n\\n // Should be set to HubPool on Ethereum, or unused on Polygon.\\n address public immutable destination;\\n\\n // WETH contract on Ethereum.\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs Token Bridger contract.\\n * @param _destination Where to send tokens to for this network.\\n * @param _l1Weth Ethereum WETH address.\\n */\\n constructor(address _destination, WETH9 _l1Weth) {\\n destination = _destination;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\\n * @notice The caller of this function must approve this contract to spend amount of token.\\n * @param token Token to bridge.\\n * @param amount Amount to bridge.\\n * @param isWrappedMatic True if token is WMATIC.\\n */\\n function send(\\n PolygonIERC20 token,\\n uint256 amount,\\n bool isWrappedMatic\\n ) public nonReentrant {\\n token.safeTransferFrom(msg.sender, address(this), amount);\\n\\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\\n token.withdraw(amount);\\n\\n // This takes the token that was withdrawn and calls withdraw on the \\\"native\\\" ERC20.\\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\\n }\\n\\n /**\\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\\n * @param token Token to send to destination.\\n */\\n function retrieve(IERC20 token) public nonReentrant {\\n token.safeTransfer(destination, token.balanceOf(address(this)));\\n }\\n\\n receive() external payable {\\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\\n }\\n}\\n\",\"keccak256\":\"0x79b3a0f440bf429abcb41d4d808892d0bd73e890334585f3ab1dd67a2bbe32cd\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60c060405234801561001057600080fd5b50604051610bbd380380610bbd83398101604081905261002f9161006b565b6000805460ff191660011790556001600160a01b039182166080521660a0526100a5565b6001600160a01b038116811461006857600080fd5b50565b6000806040838503121561007e57600080fd5b825161008981610053565b602084015190925061009a81610053565b809150509250929050565b60805160a051610ae66100d7600039600081816070015261012901526000818161018601526102450152610ae66000f3fe60806040526004361061005e5760003560e01c8063b269681d11610043578063b269681d14610174578063d124dc4f146101a8578063dc354296146101c857600080fd5b80630a79309b146100f7578063146bf4b11461011757600080fd5b366100f25760005460ff16156100f0577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156100d657600080fd5b505af11580156100ea573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561010357600080fd5b506100f0610112366004610974565b6101de565b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561018057600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101b457600080fd5b506100f06101c336600461099f565b610318565b3480156101d457600080fd5b5061014b61101081565b6101e6610499565b610213600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526102e5907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c791906109e1565b73ffffffffffffffffffffffffffffffffffffffff8416919061050c565b610315600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b610320610499565b61034d600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61036f73ffffffffffffffffffffffffffffffffffffffff84163330856105e0565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d90602401600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b505050508015610464576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905261101090632e1a7d4d9084906024016000604051808303818588803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b50505050505b610494600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b505050565b60005460ff1661050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104949084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610644565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261063e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161055e565b50505050565b60006106a6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107509092919063ffffffff16565b80519091501561049457808060200190518101906106c491906109fa565b610494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610501565b606061075f8484600085610769565b90505b9392505050565b6060824710156107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610501565b73ffffffffffffffffffffffffffffffffffffffff85163b610879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610501565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108a29190610a43565b60006040518083038185875af1925050503d80600081146108df576040519150601f19603f3d011682016040523d82523d6000602084013e6108e4565b606091505b50915091506108f48282866108ff565b979650505050505050565b6060831561090e575081610762565b82511561091e5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105019190610a5f565b73ffffffffffffffffffffffffffffffffffffffff8116811461031557600080fd5b60006020828403121561098657600080fd5b813561076281610952565b801515811461031557600080fd5b6000806000606084860312156109b457600080fd5b83356109bf81610952565b92506020840135915060408401356109d681610991565b809150509250925092565b6000602082840312156109f357600080fd5b5051919050565b600060208284031215610a0c57600080fd5b815161076281610991565b60005b83811015610a32578181015183820152602001610a1a565b8381111561063e5750506000910152565b60008251610a55818460208701610a17565b9190910192915050565b6020815260008251806020840152610a7e816040850160208701610a17565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220a6bfbc7a1aefd28bea6fd266df05752c1c618d43ebe6b51f137c909303fc674f64736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061005e5760003560e01c8063b269681d11610043578063b269681d14610174578063d124dc4f146101a8578063dc354296146101c857600080fd5b80630a79309b146100f7578063146bf4b11461011757600080fd5b366100f25760005460ff16156100f0577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b1580156100d657600080fd5b505af11580156100ea573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561010357600080fd5b506100f0610112366004610974565b6101de565b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561018057600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101b457600080fd5b506100f06101c336600461099f565b610318565b3480156101d457600080fd5b5061014b61101081565b6101e6610499565b610213600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526102e5907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c791906109e1565b73ffffffffffffffffffffffffffffffffffffffff8416919061050c565b610315600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b610320610499565b61034d600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61036f73ffffffffffffffffffffffffffffffffffffffff84163330856105e0565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff841690632e1a7d4d90602401600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b505050508015610464576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905261101090632e1a7d4d9084906024016000604051808303818588803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b50505050505b610494600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b505050565b60005460ff1661050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104949084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610644565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261063e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161055e565b50505050565b60006106a6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107509092919063ffffffff16565b80519091501561049457808060200190518101906106c491906109fa565b610494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610501565b606061075f8484600085610769565b90505b9392505050565b6060824710156107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610501565b73ffffffffffffffffffffffffffffffffffffffff85163b610879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610501565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108a29190610a43565b60006040518083038185875af1925050503d80600081146108df576040519150601f19603f3d011682016040523d82523d6000602084013e6108e4565b606091505b50915091506108f48282866108ff565b979650505050505050565b6060831561090e575081610762565b82511561091e5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105019190610a5f565b73ffffffffffffffffffffffffffffffffffffffff8116811461031557600080fd5b60006020828403121561098657600080fd5b813561076281610952565b801515811461031557600080fd5b6000806000606084860312156109b457600080fd5b83356109bf81610952565b92506020840135915060408401356109d681610991565b809150509250925092565b6000602082840312156109f357600080fd5b5051919050565b600060208284031215610a0c57600080fd5b815161076281610991565b60005b83811015610a32578181015183820152602001610a1a565b8381111561063e5750506000910152565b60008251610a55818460208701610a17565b9190910192915050565b6020815260008251806020840152610a7e816040850160208701610a17565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220a6bfbc7a1aefd28bea6fd266df05752c1c618d43ebe6b51f137c909303fc674f64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/Polygon_Adapter.json b/deployments/rinkeby/Polygon_Adapter.json index f3d8cf1a..81af2414 100644 --- a/deployments/rinkeby/Polygon_Adapter.json +++ b/deployments/rinkeby/Polygon_Adapter.json @@ -181,7 +181,7 @@ ], "numDeployments": 1, "solcInputHash": "c8b9349311d8b5049b613ac98eb998d0", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_fxStateSender\":\"FxStateSender Polygon system helper contract.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system helper contract.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface IRootChainManager {\\n function depositEtherFor(address user) external payable;\\n\\n function depositFor(\\n address user,\\n address rootToken,\\n bytes calldata depositData\\n ) external;\\n}\\n\\ninterface IFxStateSender {\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\n}\\n\\n/**\\n * @notice Sends cross chain messages Polygon L2 network.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Polygon_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n IRootChainManager public immutable rootChainManager;\\n IFxStateSender public immutable fxStateSender;\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _rootChainManager RootChainManager Polygon system helper contract.\\n * @param _fxStateSender FxStateSender Polygon system helper contract.\\n * @param _l1Weth WETH address on L1.\\n */\\n constructor(\\n IRootChainManager _rootChainManager,\\n IFxStateSender _fxStateSender,\\n WETH9 _l1Weth\\n ) {\\n rootChainManager = _rootChainManager;\\n fxStateSender = _fxStateSender;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Polygon.\\n * @param target Contract on Polygon that will receive message.\\n * @param message Data to send to target.\\n */\\n\\n function relayMessage(address target, bytes memory message) external payable override {\\n fxStateSender.sendMessageToChild(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Polygon.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n rootChainManager.depositEtherFor{ value: amount }(to);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d47c68dbc8612ab9959918f1d085461bc6765e033efad68e95f2ae4e2441cf6\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"_rootChainManager\",\"type\":\"address\"},{\"internalType\":\"contract IFxStateSender\",\"name\":\"_fxStateSender\",\"type\":\"address\"},{\"internalType\":\"contract WETH9\",\"name\":\"_l1Weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TokensRelayed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"fxStateSender\",\"outputs\":[{\"internalType\":\"contract IFxStateSender\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Weth\",\"outputs\":[{\"internalType\":\"contract WETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"relayTokens\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChainManager\",\"outputs\":[{\"internalType\":\"contract IRootChainManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Public functions calling external contracts do not guard against reentrancy because they are expected to be called via delegatecall, which will execute this contract's logic within the context of the originating contract. For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods that call this contract's logic guard against reentrancy.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_fxStateSender\":\"FxStateSender Polygon system helper contract.\",\"_l1Weth\":\"WETH address on L1.\",\"_rootChainManager\":\"RootChainManager Polygon system helper contract.\"}},\"relayMessage(address,bytes)\":{\"params\":{\"message\":\"Data to send to target.\",\"target\":\"Contract on Polygon that will receive message.\"}},\"relayTokens(address,address,uint256,address)\":{\"params\":{\"amount\":\"Amount of L1 tokens to deposit and L2 tokens to receive.\",\"l1Token\":\"L1 token to deposit.\",\"l2Token\":\"L2 token to receive.\",\"to\":\"Bridge recipient.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructs new Adapter.\"},\"relayMessage(address,bytes)\":{\"notice\":\"Send cross-chain message to target on Polygon.\"},\"relayTokens(address,address,uint256,address)\":{\"notice\":\"Bridge tokens to Polygon.\"}},\"notice\":\"Sends cross chain messages Polygon L2 network.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/chain-adapters/Polygon_Adapter.sol\":\"Polygon_Adapter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbbc8ac883ac3c0078ce5ad3e288fbb3ffcc8a30c3a98c0fda0114d64fc44fca2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"contracts/chain-adapters/Polygon_Adapter.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/AdapterInterface.sol\\\";\\nimport \\\"../interfaces/WETH9.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\ninterface IRootChainManager {\\n function depositEtherFor(address user) external payable;\\n\\n function depositFor(\\n address user,\\n address rootToken,\\n bytes calldata depositData\\n ) external;\\n}\\n\\ninterface IFxStateSender {\\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\\n}\\n\\n/**\\n * @notice Sends cross chain messages Polygon L2 network.\\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\\n * that call this contract's logic guard against reentrancy.\\n */\\ncontract Polygon_Adapter is AdapterInterface {\\n using SafeERC20 for IERC20;\\n IRootChainManager public immutable rootChainManager;\\n IFxStateSender public immutable fxStateSender;\\n WETH9 public immutable l1Weth;\\n\\n /**\\n * @notice Constructs new Adapter.\\n * @param _rootChainManager RootChainManager Polygon system helper contract.\\n * @param _fxStateSender FxStateSender Polygon system helper contract.\\n * @param _l1Weth WETH address on L1.\\n */\\n constructor(\\n IRootChainManager _rootChainManager,\\n IFxStateSender _fxStateSender,\\n WETH9 _l1Weth\\n ) {\\n rootChainManager = _rootChainManager;\\n fxStateSender = _fxStateSender;\\n l1Weth = _l1Weth;\\n }\\n\\n /**\\n * @notice Send cross-chain message to target on Polygon.\\n * @param target Contract on Polygon that will receive message.\\n * @param message Data to send to target.\\n */\\n\\n function relayMessage(address target, bytes memory message) external payable override {\\n fxStateSender.sendMessageToChild(target, message);\\n emit MessageRelayed(target, message);\\n }\\n\\n /**\\n * @notice Bridge tokens to Polygon.\\n * @param l1Token L1 token to deposit.\\n * @param l2Token L2 token to receive.\\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\\n * @param to Bridge recipient.\\n */\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable override {\\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\\n if (l1Token == address(l1Weth)) {\\n l1Weth.withdraw(amount);\\n rootChainManager.depositEtherFor{ value: amount }(to);\\n } else {\\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\\n }\\n emit TokensRelayed(l1Token, l2Token, amount, to);\\n }\\n}\\n\",\"keccak256\":\"0x0d47c68dbc8612ab9959918f1d085461bc6765e033efad68e95f2ae4e2441cf6\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/AdapterInterface.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\\n */\\n\\ninterface AdapterInterface {\\n event MessageRelayed(address target, bytes message);\\n\\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\\n\\n function relayMessage(address target, bytes memory message) external payable;\\n\\n function relayTokens(\\n address l1Token,\\n address l2Token,\\n uint256 amount,\\n address to\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xbd7091006acbdfe72b21ce985f964f0682a2316d9d3b38967beeb55f4ae5118c\",\"license\":\"AGPL-3.0-only\"},\"contracts/interfaces/WETH9.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.0;\\n\\ninterface WETH9 {\\n function withdraw(uint256 wad) external;\\n\\n function deposit() external payable;\\n\\n function balanceOf(address guy) external view returns (uint256 wad);\\n\\n function transfer(address guy, uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x7b444d0840b1f76eee9bf39d74830f70644395613b96cce2d80fc50785a82eaa\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", "bytecode": "0x60e060405234801561001057600080fd5b50604051610dc7380380610dc783398101604081905261002f91610064565b6001600160a01b0392831660805290821660a0521660c0526100b1565b6001600160a01b038116811461006157600080fd5b50565b60008060006060848603121561007957600080fd5b83516100848161004c565b60208501519093506100958161004c565b60408501519092506100a68161004c565b809150509250925092565b60805160a05160c051610cbf6101086000396000818160710152818161014e01526101ce01526000818160e3015261047b0152600081816101170152818161028201528181610303015261032a0152610cbf6000f3fe60806040526004361061005a5760003560e01c8063a996cabb11610043578063a996cabb146100d1578063bd07018d14610105578063e6eb8ade1461013957600080fd5b8063146bf4b11461005f57806352c8c75c146100bc575b600080fd5b34801561006b57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100cf6100ca36600461099d565b61014c565b005b3480156100dd57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b34801561011157600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b6100cf610147366004610a19565b61043e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036102e7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561022757600080fd5b505af115801561023b573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b1580156102c957600080fd5b505af11580156102dd573d6000803e3d6000fd5b50505050506103d9565b61032873ffffffffffffffffffffffffffffffffffffffff85167f000000000000000000000000000000000000000000000000000000000000000084610521565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161037991815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016103a693929190610b6f565b600060405180830381600087803b1580156103c057600080fd5b505af11580156103d4573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906104b29085908590600401610bb1565b600060405180830381600087803b1580156104cc57600080fd5b505af11580156104e0573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610515929190610bb1565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190610be0565b6105c69190610bf9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061065690859061065c565b50505050565b60006106be826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107729092919063ffffffff16565b80519091501561076d57808060200190518101906106dc9190610c38565b61076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610781848460008561078b565b90505b9392505050565b60608247101561081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610764565b73ffffffffffffffffffffffffffffffffffffffff85163b61089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610764565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108c49190610c5a565b60006040518083038185875af1925050503d8060008114610901576040519150601f19603f3d011682016040523d82523d6000602084013e610906565b606091505b5091509150610916828286610921565b979650505050505050565b60608315610930575081610784565b8251156109405782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107649190610c76565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099857600080fd5b919050565b600080600080608085870312156109b357600080fd5b6109bc85610974565b93506109ca60208601610974565b9250604085013591506109df60608601610974565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610a2c57600080fd5b610a3583610974565b9150602083013567ffffffffffffffff80821115610a5257600080fd5b818501915085601f830112610a6657600080fd5b813581811115610a7857610a786109ea565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610abe57610abe6109ea565b81604052828152886020848701011115610ad757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610b14578181015183820152602001610afc565b838111156106565750506000910152565b60008151808452610b3d816020860160208601610af9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610ba86060830184610b25565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006107816040830184610b25565b600060208284031215610bf257600080fd5b5051919050565b60008219821115610c33577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610c4a57600080fd5b8151801515811461078457600080fd5b60008251610c6c818460208701610af9565b9190910192915050565b6020815260006107846020830184610b2556fea2646970667358221220314a1e3672715e1c9fd64c503fc29f347e18573590a2881a1f8a69e6e8bfabd264736f6c634300080d0033", "deployedBytecode": "0x60806040526004361061005a5760003560e01c8063a996cabb11610043578063a996cabb146100d1578063bd07018d14610105578063e6eb8ade1461013957600080fd5b8063146bf4b11461005f57806352c8c75c146100bc575b600080fd5b34801561006b57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100cf6100ca36600461099d565b61014c565b005b3480156100dd57600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b34801561011157600080fd5b506100937f000000000000000000000000000000000000000000000000000000000000000081565b6100cf610147366004610a19565b61043e565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036102e7576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561022757600080fd5b505af115801561023b573d6000803e3d6000fd5b50506040517f4faa8a2600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169250634faa8a26915084906024016000604051808303818588803b1580156102c957600080fd5b505af11580156102dd573d6000803e3d6000fd5b50505050506103d9565b61032873ffffffffffffffffffffffffffffffffffffffff85167f000000000000000000000000000000000000000000000000000000000000000084610521565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3dec8fb82868560405160200161037991815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016103a693929190610b6f565b600060405180830381600087803b1580156103c057600080fd5b505af11580156103d4573d6000803e3d6000fd5b505050505b6040805173ffffffffffffffffffffffffffffffffffffffff868116825285811660208301528183018590528316606082015290517fd7e09655439c3932e55857df3220186e5a7f0980825f20691c2b35d941dee75b9181900360800190a150505050565b6040517fb472047700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b4720477906104b29085908590600401610bb1565b600060405180830381600087803b1580156104cc57600080fd5b505af11580156104e0573d6000803e3d6000fd5b505050507f9e6c52944e331ba6270e7fe4cea2a4086bae8f7a27e1cdba07f416806f5d0ac48282604051610515929190610bb1565b60405180910390a15050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190610be0565b6105c69190610bf9565b6040805173ffffffffffffffffffffffffffffffffffffffff8616602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290915061065690859061065c565b50505050565b60006106be826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107729092919063ffffffff16565b80519091501561076d57808060200190518101906106dc9190610c38565b61076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b6060610781848460008561078b565b90505b9392505050565b60608247101561081d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610764565b73ffffffffffffffffffffffffffffffffffffffff85163b61089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610764565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516108c49190610c5a565b60006040518083038185875af1925050503d8060008114610901576040519150601f19603f3d011682016040523d82523d6000602084013e610906565b606091505b5091509150610916828286610921565b979650505050505050565b60608315610930575081610784565b8251156109405782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107649190610c76565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099857600080fd5b919050565b600080600080608085870312156109b357600080fd5b6109bc85610974565b93506109ca60208601610974565b9250604085013591506109df60608601610974565b905092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215610a2c57600080fd5b610a3583610974565b9150602083013567ffffffffffffffff80821115610a5257600080fd5b818501915085601f830112610a6657600080fd5b813581811115610a7857610a786109ea565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610abe57610abe6109ea565b81604052828152886020848701011115610ad757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b83811015610b14578181015183820152602001610afc565b838111156106565750506000910152565b60008151808452610b3d816020860160208601610af9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610ba86060830184610b25565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006107816040830184610b25565b600060208284031215610bf257600080fd5b5051919050565b60008219821115610c33577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600060208284031215610c4a57600080fd5b8151801515811461078457600080fd5b60008251610c6c818460208701610af9565b9190910192915050565b6020815260006107846020830184610b2556fea2646970667358221220314a1e3672715e1c9fd64c503fc29f347e18573590a2881a1f8a69e6e8bfabd264736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/RateModelStore.json b/deployments/rinkeby/RateModelStore.json index f00e55f5..6f142271 100644 --- a/deployments/rinkeby/RateModelStore.json +++ b/deployments/rinkeby/RateModelStore.json @@ -163,7 +163,7 @@ "args": [], "numDeployments": 1, "solcInputHash": "1bf8793c065ccb196e5a60f53c731ca8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"UpdatedRateModel\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenRateModels\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"updateRateModel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust the structure in the future.\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateRateModel(address,string)\":{\"params\":{\"l1Token\":\"the l1 token rate model to update.\",\"rateModel\":\"the updated rate model.\"}}},\"title\":\"Maps rate model objects to L1 token.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateRateModel(address,string)\":{\"notice\":\"Updates rate model string for L1 token.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RateModelStore.sol\":\"RateModelStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/RateModelStore.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Maps rate model objects to L1 token.\\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\\n * the structure in the future.\\n */\\ncontract RateModelStore is Ownable, MultiCaller {\\n mapping(address => string) public l1TokenRateModels;\\n\\n event UpdatedRateModel(address indexed l1Token, string rateModel);\\n\\n /**\\n * @notice Updates rate model string for L1 token.\\n * @param l1Token the l1 token rate model to update.\\n * @param rateModel the updated rate model.\\n */\\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\\n l1TokenRateModels[l1Token] = rateModel;\\n emit UpdatedRateModel(l1Token, rateModel);\\n }\\n}\\n\",\"keccak256\":\"0xa476c6f657c69316a86ceddbbffb29e77d6550598a3946db43970b9493aa0b16\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"UpdatedRateModel\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"l1TokenRateModels\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"rateModel\",\"type\":\"string\"}],\"name\":\"updateRateModel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust the structure in the future.\",\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"updateRateModel(address,string)\":{\"params\":{\"l1Token\":\"the l1 token rate model to update.\",\"rateModel\":\"the updated rate model.\"}}},\"title\":\"Maps rate model objects to L1 token.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"updateRateModel(address,string)\":{\"notice\":\"Updates rate model string for L1 token.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RateModelStore.sol\":\"RateModelStore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@uma/core/contracts/common/implementation/MultiCaller.sol\":{\"content\":\"// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\\npragma solidity ^0.8.0;\\n\\n/// @title MultiCaller\\n/// @notice Enables calling multiple methods in a single call to the contract\\ncontract MultiCaller {\\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\\n require(msg.value == 0, \\\"Only multicall with 0 value\\\");\\n results = new bytes[](data.length);\\n for (uint256 i = 0; i < data.length; i++) {\\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n if (!success) {\\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n if (result.length < 68) revert();\\n assembly {\\n result := add(result, 0x04)\\n }\\n revert(abi.decode(result, (string)));\\n }\\n\\n results[i] = result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x31f18055b14fd9eeb459c6d6a88d1a60921bf3755031f6db4b709c3e01d078f7\"},\"contracts/RateModelStore.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity ^0.8.0;\\n\\nimport \\\"@uma/core/contracts/common/implementation/MultiCaller.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/**\\n * @title Maps rate model objects to L1 token.\\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\\n * the structure in the future.\\n */\\ncontract RateModelStore is Ownable, MultiCaller {\\n mapping(address => string) public l1TokenRateModels;\\n\\n event UpdatedRateModel(address indexed l1Token, string rateModel);\\n\\n /**\\n * @notice Updates rate model string for L1 token.\\n * @param l1Token the l1 token rate model to update.\\n * @param rateModel the updated rate model.\\n */\\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\\n l1TokenRateModels[l1Token] = rateModel;\\n emit UpdatedRateModel(l1Token, rateModel);\\n }\\n}\\n\",\"keccak256\":\"0xa476c6f657c69316a86ceddbbffb29e77d6550598a3946db43970b9493aa0b16\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610cc68061007e6000396000f3fe6080604052600436106100655760003560e01c80638da5cb5b116100435780638da5cb5b146100d7578063ac9650d81461010c578063f2fde38b1461012c57600080fd5b80630be5512b1461006a578063715018a61461008c57806374cc3f3e146100a1575b600080fd5b34801561007657600080fd5b5061008a610085366004610887565b61014c565b005b34801561009857600080fd5b5061008a61025b565b3480156100ad57600080fd5b506100c16100bc366004610918565b6102e8565b6040516100ce91906109b4565b60405180910390f35b3480156100e357600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ce565b61011f61011a3660046109c7565b610382565b6040516100ce9190610a3c565b34801561013857600080fd5b5061008a610147366004610918565b61055c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160209081526040909120825161020892840190610701565b508173ffffffffffffffffffffffffffffffffffffffff167fffbed0e73ca0e16b79488dd92e2cea865dd04b08d41dd27f05abbad9584581388260405161024f91906109b4565b60405180910390a25050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b6102e6600061068c565b565b6001602052600090815260409020805461030190610abc565b80601f016020809104026020016040519081016040528092919081815260200182805461032d90610abc565b801561037a5780601f1061034f5761010080835404028352916020019161037a565b820191906000526020600020905b81548152906001019060200180831161035d57829003601f168201915b505050505081565b606034156103ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016101c9565b8167ffffffffffffffff811115610405576104056107c3565b60405190808252806020026020018201604052801561043857816020015b60608152602001906001900390816104235790505b50905060005b82811015610555576000803086868581811061045c5761045c610b0f565b905060200281019061046e9190610b3e565b60405161047c929190610baa565b600060405180830381855af49150503d80600081146104b7576040519150601f19603f3d011682016040523d82523d6000602084013e6104bc565b606091505b509150915081610522576044815110156104d557600080fd5b600481019050808060200190518101906104ef9190610bba565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c991906109b4565b8084848151811061053557610535610b0f565b60200260200101819052505050808061054d90610c31565b91505061043e565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b73ffffffffffffffffffffffffffffffffffffffff8116610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c9565b6106898161068c565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461070d90610abc565b90600052602060002090601f01602090048101928261072f5760008555610775565b82601f1061074857805160ff1916838001178555610775565b82800160010185558215610775579182015b8281111561077557825182559160200191906001019061075a565b50610781929150610785565b5090565b5b808211156107815760008155600101610786565b803573ffffffffffffffffffffffffffffffffffffffff811681146107be57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610839576108396107c3565b604052919050565b600067ffffffffffffffff82111561085b5761085b6107c3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561089a57600080fd5b6108a38361079a565b9150602083013567ffffffffffffffff8111156108bf57600080fd5b8301601f810185136108d057600080fd5b80356108e36108de82610841565b6107f2565b8181528660208385010111156108f857600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561092a57600080fd5b6109338261079a565b9392505050565b60005b8381101561095557818101518382015260200161093d565b83811115610964576000848401525b50505050565b6000815180845261098281602086016020860161093a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610933602083018461096a565b600080602083850312156109da57600080fd5b823567ffffffffffffffff808211156109f257600080fd5b818501915085601f830112610a0657600080fd5b813581811115610a1557600080fd5b8660208260051b8501011115610a2a57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610aaf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610a9d85835161096a565b94509285019290850190600101610a63565b5092979650505050505050565b600181811c90821680610ad057607f821691505b602082108103610b09577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b7357600080fd5b83018035915067ffffffffffffffff821115610b8e57600080fd5b602001915036819003821315610ba357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610bcc57600080fd5b815167ffffffffffffffff811115610be357600080fd5b8201601f81018413610bf457600080fd5b8051610c026108de82610841565b818152856020838501011115610c1757600080fd5b610c2882602083016020860161093a565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c89577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea26469706673582212208e5db8f43ebedc8eed583769234122bc8473aea877b1a57cffaf607e81f67c7b64736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100655760003560e01c80638da5cb5b116100435780638da5cb5b146100d7578063ac9650d81461010c578063f2fde38b1461012c57600080fd5b80630be5512b1461006a578063715018a61461008c57806374cc3f3e146100a1575b600080fd5b34801561007657600080fd5b5061008a610085366004610887565b61014c565b005b34801561009857600080fd5b5061008a61025b565b3480156100ad57600080fd5b506100c16100bc366004610918565b6102e8565b6040516100ce91906109b4565b60405180910390f35b3480156100e357600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ce565b61011f61011a3660046109c7565b610382565b6040516100ce9190610a3c565b34801561013857600080fd5b5061008a610147366004610918565b61055c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160209081526040909120825161020892840190610701565b508173ffffffffffffffffffffffffffffffffffffffff167fffbed0e73ca0e16b79488dd92e2cea865dd04b08d41dd27f05abbad9584581388260405161024f91906109b4565b60405180910390a25050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b6102e6600061068c565b565b6001602052600090815260409020805461030190610abc565b80601f016020809104026020016040519081016040528092919081815260200182805461032d90610abc565b801561037a5780601f1061034f5761010080835404028352916020019161037a565b820191906000526020600020905b81548152906001019060200180831161035d57829003601f168201915b505050505081565b606034156103ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f6e6c79206d756c746963616c6c207769746820302076616c7565000000000060448201526064016101c9565b8167ffffffffffffffff811115610405576104056107c3565b60405190808252806020026020018201604052801561043857816020015b60608152602001906001900390816104235790505b50905060005b82811015610555576000803086868581811061045c5761045c610b0f565b905060200281019061046e9190610b3e565b60405161047c929190610baa565b600060405180830381855af49150503d80600081146104b7576040519150601f19603f3d011682016040523d82523d6000602084013e6104bc565b606091505b509150915081610522576044815110156104d557600080fd5b600481019050808060200190518101906104ef9190610bba565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c991906109b4565b8084848151811061053557610535610b0f565b60200260200101819052505050808061054d90610c31565b91505061043e565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c9565b73ffffffffffffffffffffffffffffffffffffffff8116610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c9565b6106898161068c565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805461070d90610abc565b90600052602060002090601f01602090048101928261072f5760008555610775565b82601f1061074857805160ff1916838001178555610775565b82800160010185558215610775579182015b8281111561077557825182559160200191906001019061075a565b50610781929150610785565b5090565b5b808211156107815760008155600101610786565b803573ffffffffffffffffffffffffffffffffffffffff811681146107be57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610839576108396107c3565b604052919050565b600067ffffffffffffffff82111561085b5761085b6107c3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561089a57600080fd5b6108a38361079a565b9150602083013567ffffffffffffffff8111156108bf57600080fd5b8301601f810185136108d057600080fd5b80356108e36108de82610841565b6107f2565b8181528660208385010111156108f857600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561092a57600080fd5b6109338261079a565b9392505050565b60005b8381101561095557818101518382015260200161093d565b83811115610964576000848401525b50505050565b6000815180845261098281602086016020860161093a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610933602083018461096a565b600080602083850312156109da57600080fd5b823567ffffffffffffffff808211156109f257600080fd5b818501915085601f830112610a0657600080fd5b813581811115610a1557600080fd5b8660208260051b8501011115610a2a57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610aaf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610a9d85835161096a565b94509285019290850190600101610a63565b5092979650505050505050565b600181811c90821680610ad057607f821691505b602082108103610b09577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b7357600080fd5b83018035915067ffffffffffffffff821115610b8e57600080fd5b602001915036819003821315610ba357600080fd5b9250929050565b8183823760009101908152919050565b600060208284031215610bcc57600080fd5b815167ffffffffffffffff811115610be357600080fd5b8201601f81018413610bf457600080fd5b8051610c026108de82610841565b818152856020838501011115610c1757600080fd5b610c2882602083016020860161093a565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c89577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea26469706673582212208e5db8f43ebedc8eed583769234122bc8473aea877b1a57cffaf607e81f67c7b64736f6c634300080d0033", "devdoc": { diff --git a/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json b/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json index 81073eab..87700cfc 100644 --- a/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json +++ b/deployments/rinkeby/solcInputs/1bf8793c065ccb196e5a60f53c731ca8.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n bytes32 indexed relayHash,\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\r\n for (uint32 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint32).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 relayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayHash,\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./MerkleLib.sol\";\r\nimport \"./interfaces/WETH9.sol\";\r\nimport \"./Lockable.sol\";\r\nimport \"./SpokePoolInterface.sol\";\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/utils/Address.sol\";\r\n\r\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\r\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\r\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\r\n\r\n/**\r\n * @title SpokePool\r\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\r\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\r\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\r\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\r\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\r\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\r\n */\r\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\r\n using SafeERC20 for IERC20;\r\n using Address for address;\r\n\r\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\r\n // then this address should be set to the same owner as the HubPool and the whole system.\r\n address public crossDomainAdmin;\r\n\r\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\r\n // refunds and slow relays.\r\n address public hubPool;\r\n\r\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\r\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\r\n WETH9 public immutable wrappedNativeToken;\r\n\r\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\r\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\r\n uint32 public depositQuoteTimeBuffer = 600;\r\n\r\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\r\n uint32 public numberOfDeposits;\r\n\r\n // This contract can store as many root bundles as the HubPool chooses to publish here.\r\n RootBundle[] public rootBundles;\r\n\r\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\r\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\r\n\r\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\r\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\r\n // relay, the fees, and the agents are all parameters included in the hash key.\r\n mapping(bytes32 => uint256) public relayFills;\r\n\r\n /****************************************\r\n * EVENTS *\r\n ****************************************/\r\n event SetXDomainAdmin(address indexed newAdmin);\r\n event SetHubPool(address indexed newHubPool);\r\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\r\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\r\n event FundsDeposited(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 indexed depositId,\r\n uint32 quoteTimestamp,\r\n address indexed originToken,\r\n address recipient,\r\n address indexed depositor\r\n );\r\n event RequestedSpeedUpDeposit(\r\n uint64 newRelayerFeePct,\r\n uint32 indexed depositId,\r\n address indexed depositor,\r\n bytes depositorSignature\r\n );\r\n event FilledRelay(\r\n bytes32 indexed relayHash,\r\n uint256 amount,\r\n uint256 totalFilledAmount,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint64 realizedLpFeePct,\r\n uint32 depositId,\r\n address destinationToken,\r\n address indexed relayer,\r\n address indexed depositor,\r\n address recipient,\r\n bool isSlowRelay\r\n );\r\n event RelayedRootBundle(\r\n uint32 indexed rootBundleId,\r\n bytes32 indexed relayerRefundRoot,\r\n bytes32 indexed slowRelayRoot\r\n );\r\n event ExecutedRelayerRefundRoot(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint256[] refundAmounts,\r\n uint32 indexed rootBundleId,\r\n uint32 indexed leafId,\r\n address l2TokenAddress,\r\n address[] refundAddresses,\r\n address caller\r\n );\r\n event TokensBridged(\r\n uint256 amountToReturn,\r\n uint256 indexed chainId,\r\n uint32 indexed leafId,\r\n address indexed l2TokenAddress,\r\n address caller\r\n );\r\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\r\n\r\n /**\r\n * @notice Construct the base SpokePool.\r\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\r\n * @param _hubPool Hub pool address to set. Can be changed by admin.\r\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\r\n * @param timerAddress Timer address to set.\r\n */\r\n constructor(\r\n address _crossDomainAdmin,\r\n address _hubPool,\r\n address _wrappedNativeTokenAddress,\r\n address timerAddress\r\n ) Testable(timerAddress) {\r\n _setCrossDomainAdmin(_crossDomainAdmin);\r\n _setHubPool(_hubPool);\r\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\r\n }\r\n\r\n /****************************************\r\n * MODIFIERS *\r\n ****************************************/\r\n\r\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\r\n // appropriately.\r\n modifier onlyAdmin() {\r\n _requireAdminSender();\r\n _;\r\n }\r\n\r\n /**************************************\r\n * ADMIN FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Change cross domain admin address. Callable by admin only.\r\n * @param newCrossDomainAdmin New cross domain admin.\r\n */\r\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\r\n _setCrossDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n /**\r\n * @notice Change L1 hub pool address. Callable by admin only.\r\n * @param newHubPool New hub pool.\r\n */\r\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\r\n _setHubPool(newHubPool);\r\n }\r\n\r\n /**\r\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\r\n * @param originToken Token that depositor can deposit to this contract.\r\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\r\n * @param enabled True to enable deposits, False otherwise.\r\n */\r\n function setEnableRoute(\r\n address originToken,\r\n uint256 destinationChainId,\r\n bool enabled\r\n ) public override onlyAdmin nonReentrant {\r\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\r\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\r\n }\r\n\r\n /**\r\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\r\n * @param newDepositQuoteTimeBuffer New quote time buffer.\r\n */\r\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\r\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\r\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\r\n }\r\n\r\n /**\r\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\r\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\r\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\r\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\r\n * executeRelayerRefundLeaf().\r\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\r\n * executeSlowRelayLeaf().\r\n */\r\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\r\n uint32 rootBundleId = uint32(rootBundles.length);\r\n RootBundle storage rootBundle = rootBundles.push();\r\n rootBundle.relayerRefundRoot = relayerRefundRoot;\r\n rootBundle.slowRelayRoot = slowRelayRoot;\r\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\r\n }\r\n\r\n /**\r\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\r\n * SpokePool.\r\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\r\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\r\n */\r\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\r\n delete rootBundles[rootBundleId];\r\n emit EmergencyDeleteRootBundle(rootBundleId);\r\n }\r\n\r\n /**************************************\r\n * DEPOSITOR FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\r\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\r\n * token mapping is stored on the L1 HubPool.\r\n * @notice The caller must first approve this contract to spend amount of originToken.\r\n * @notice The originToken => destinationChainId must be enabled.\r\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\r\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\r\n * @param recipient Address to receive funds at on destination chain.\r\n * @param originToken Token to lock into this contract to initiate deposit.\r\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\r\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\r\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\r\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\r\n * to LP pool on HubPool.\r\n */\r\n function deposit(\r\n address recipient,\r\n address originToken,\r\n uint256 amount,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 quoteTimestamp\r\n ) public payable override nonReentrant {\r\n // Check that deposit route is enabled.\r\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\r\n\r\n // We limit the relay fees to prevent the user spending all their funds on fees.\r\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\r\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\r\n // buffer of this contract's block time to allow for this variance.\r\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\r\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\r\n require(\r\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\r\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\r\n \"invalid quote time\"\r\n );\r\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\r\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\r\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\r\n require(msg.value == amount, \"msg.value must match amount\");\r\n wrappedNativeToken.deposit{ value: msg.value }();\r\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\r\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\r\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\r\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\r\n\r\n _emitDeposit(\r\n amount,\r\n chainId(),\r\n destinationChainId,\r\n relayerFeePct,\r\n numberOfDeposits,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n msg.sender\r\n );\r\n\r\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\r\n // @dev: Use pre-increment to save gas:\r\n // i++ --> Load, Store, Add, Store\r\n // ++i --> Load, Add, Store\r\n ++numberOfDeposits;\r\n }\r\n\r\n /**\r\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\r\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\r\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\r\n * update fee message.\r\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\r\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\r\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\r\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\r\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\r\n * did in fact submit a relay.\r\n * @param newRelayerFeePct New relayer fee that relayers can use.\r\n * @param depositId Deposit to update fee for that originated in this contract.\r\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\r\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\r\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\r\n */\r\n function speedUpDeposit(\r\n address depositor,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\r\n\r\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\r\n // from the following event to submit a fill with an updated fee %.\r\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\r\n }\r\n\r\n /**************************************\r\n * RELAYER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\r\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\r\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\r\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\r\n * then relayer will not receive any refund.\r\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\r\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\r\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\r\n * as described in a UMIP linked to the HubPool's identifier.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n */\r\n function fillRelay(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId\r\n ) public nonReentrant {\r\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\r\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\r\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\r\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\r\n }\r\n\r\n /**\r\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\r\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\r\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\r\n * send recipient the full relay amount.\r\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\r\n * passed.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param depositorSignature Depositor-signed message containing updated fee %.\r\n */\r\n function fillRelayWithUpdatedFee(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 maxTokensToSend,\r\n uint256 repaymentChainId,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) public override nonReentrant {\r\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\r\n\r\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId,\r\n originChainId: originChainId,\r\n destinationChainId: chainId()\r\n });\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\r\n\r\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\r\n }\r\n\r\n /**************************************\r\n * DATA WORKER FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\r\n * relay to the recipient, less fees.\r\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\r\n * the caller from executing a slow relay intended for another chain on this chain.\r\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\r\n * @param recipient Specified recipient on this chain.\r\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\r\n * and this chain ID via a mapping on the HubPool.\r\n * @param amount Full size of the deposit.\r\n * @param originChainId Chain of SpokePool where deposit originated.\r\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\r\n * quote time.\r\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\r\n * @param depositId Unique deposit ID on origin spoke pool.\r\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\r\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\r\n */\r\n function executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeSlowRelayLeaf(\r\n depositor,\r\n recipient,\r\n destinationToken,\r\n amount,\r\n originChainId,\r\n chainId(),\r\n realizedLpFeePct,\r\n relayerFeePct,\r\n depositId,\r\n rootBundleId,\r\n proof\r\n );\r\n }\r\n\r\n /**\r\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\r\n * sent to the recipient plus a relayer fee.\r\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\r\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\r\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\r\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\r\n */\r\n function executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) public virtual override nonReentrant {\r\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\r\n }\r\n\r\n /**************************************\r\n * VIEW FUNCTIONS *\r\n **************************************/\r\n\r\n /**\r\n * @notice Returns chain ID for this network.\r\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\r\n */\r\n function chainId() public view virtual override returns (uint256) {\r\n return block.chainid;\r\n }\r\n\r\n /**************************************\r\n * INTERNAL FUNCTIONS *\r\n **************************************/\r\n\r\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\r\n // transfers.\r\n function _executeRelayerRefundLeaf(\r\n uint32 rootBundleId,\r\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\r\n bytes32[] memory proof\r\n ) internal {\r\n // Check integrity of leaf structure:\r\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\r\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\r\n\r\n RootBundle storage rootBundle = rootBundles[rootBundleId];\r\n\r\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\r\n // Note: This should revert if the relayerRefundRoot is uninitialized.\r\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\r\n\r\n // Verify the leafId in the leaf has not yet been claimed.\r\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\r\n\r\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\r\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\r\n\r\n // Send each relayer refund address the associated refundAmount for the L2 token address.\r\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\r\n uint32 length = uint32(relayerRefundLeaf.refundAmounts.length);\r\n for (uint32 i = 0; i < length; ) {\r\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\r\n if (amount > 0)\r\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\r\n\r\n // OK because we assume refund array length won't be > types(uint32).max.\r\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\r\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\r\n // not make it to this stage.\r\n\r\n unchecked {\r\n ++i;\r\n }\r\n }\r\n\r\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\r\n // chain-specific bridging method.\r\n if (relayerRefundLeaf.amountToReturn > 0) {\r\n _bridgeTokensToHubPool(relayerRefundLeaf);\r\n\r\n emit TokensBridged(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n msg.sender\r\n );\r\n }\r\n\r\n emit ExecutedRelayerRefundRoot(\r\n relayerRefundLeaf.amountToReturn,\r\n relayerRefundLeaf.chainId,\r\n relayerRefundLeaf.refundAmounts,\r\n rootBundleId,\r\n relayerRefundLeaf.leafId,\r\n relayerRefundLeaf.l2TokenAddress,\r\n relayerRefundLeaf.refundAddresses,\r\n msg.sender\r\n );\r\n }\r\n\r\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\r\n function _executeSlowRelayLeaf(\r\n address depositor,\r\n address recipient,\r\n address destinationToken,\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 realizedLpFeePct,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 rootBundleId,\r\n bytes32[] memory proof\r\n ) internal {\r\n RelayData memory relayData = RelayData({\r\n depositor: depositor,\r\n recipient: recipient,\r\n destinationToken: destinationToken,\r\n amount: amount,\r\n originChainId: originChainId,\r\n destinationChainId: destinationChainId,\r\n realizedLpFeePct: realizedLpFeePct,\r\n relayerFeePct: relayerFeePct,\r\n depositId: depositId\r\n });\r\n\r\n require(\r\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\r\n \"Invalid proof\"\r\n );\r\n\r\n bytes32 relayHash = _getRelayHash(relayData);\r\n\r\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\r\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\r\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\r\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\r\n\r\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\r\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\r\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\r\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\r\n }\r\n\r\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\r\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\r\n crossDomainAdmin = newCrossDomainAdmin;\r\n emit SetXDomainAdmin(newCrossDomainAdmin);\r\n }\r\n\r\n function _setHubPool(address newHubPool) internal {\r\n require(newHubPool != address(0), \"Bad hub pool address\");\r\n hubPool = newHubPool;\r\n emit SetHubPool(newHubPool);\r\n }\r\n\r\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\r\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\r\n\r\n function _verifyUpdateRelayerFeeMessage(\r\n address depositor,\r\n uint256 originChainId,\r\n uint64 newRelayerFeePct,\r\n uint32 depositId,\r\n bytes memory depositorSignature\r\n ) internal view {\r\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\r\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\r\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\r\n // in case this contract is upgraded.\r\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\r\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\r\n bytes32 expectedDepositorMessageHash = keccak256(\r\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\r\n );\r\n\r\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\r\n // If the depositor signed a message with a different updated fee (or any other param included in the\r\n // above keccak156 hash), then this will revert.\r\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\r\n\r\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\r\n }\r\n\r\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\r\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\r\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\r\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\r\n function _verifyDepositorUpdateFeeMessage(\r\n address depositor,\r\n bytes32 ethSignedMessageHash,\r\n bytes memory depositorSignature\r\n ) internal view virtual {\r\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\r\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\r\n // chain does not have a parallel on this destination chain.\r\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\r\n }\r\n\r\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (1e18 * amount) / (1e18 - feesPct);\r\n }\r\n\r\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\r\n return (amount * (1e18 - feesPct)) / 1e18;\r\n }\r\n\r\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\r\n return keccak256(abi.encode(relayData));\r\n }\r\n\r\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\r\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\r\n if (address(to).isContract()) {\r\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\r\n } else {\r\n wrappedNativeToken.withdraw(amount);\r\n to.transfer(amount);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\r\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\r\n * and send to the recipient.\r\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\r\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\r\n */\r\n function _fillRelay(\r\n bytes32 relayHash,\r\n RelayData memory relayData,\r\n uint256 maxTokensToSend,\r\n uint64 updatableRelayerFeePct,\r\n bool useContractFunds\r\n ) internal returns (uint256 fillAmountPreFees) {\r\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\r\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\r\n // computing the amount pre fees runs into divide-by-0 issues.\r\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\r\n\r\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\r\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\r\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\r\n\r\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\r\n if (maxTokensToSend == 0) return 0;\r\n\r\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\r\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\r\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\r\n // of the full relay size, the caller would need to send 10 tokens to the user.\r\n fillAmountPreFees = _computeAmountPreFees(\r\n maxTokensToSend,\r\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\r\n );\r\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\r\n // we'll pull exactly enough tokens to complete the relay.\r\n uint256 amountToSend = maxTokensToSend;\r\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\r\n if (amountRemainingInRelay < fillAmountPreFees) {\r\n fillAmountPreFees = amountRemainingInRelay;\r\n\r\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\r\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\r\n // this is a slow relay.\r\n amountToSend = _computeAmountPostFees(\r\n fillAmountPreFees,\r\n relayData.realizedLpFeePct + updatableRelayerFeePct\r\n );\r\n }\r\n\r\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\r\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\r\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\r\n relayFills[relayHash] += fillAmountPreFees;\r\n\r\n // If relay token is wrappedNativeToken then unwrap and send native token.\r\n if (relayData.destinationToken == address(wrappedNativeToken)) {\r\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\r\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\r\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\r\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\r\n // need to unwrap it to native token before sending to the user.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\r\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\r\n // Else, this is a normal ERC20 token. Send to recipient.\r\n } else {\r\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\r\n if (!useContractFunds)\r\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\r\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\r\n }\r\n }\r\n\r\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\r\n function _emitFillRelay(\r\n bytes32 relayHash,\r\n uint256 fillAmount,\r\n uint256 repaymentChainId,\r\n uint64 relayerFeePct,\r\n RelayData memory relayData,\r\n bool isSlowRelay\r\n ) internal {\r\n emit FilledRelay(\r\n relayHash,\r\n relayData.amount,\r\n relayFills[relayHash],\r\n fillAmount,\r\n repaymentChainId,\r\n relayData.originChainId,\r\n relayData.destinationChainId,\r\n relayerFeePct,\r\n relayData.realizedLpFeePct,\r\n relayData.depositId,\r\n relayData.destinationToken,\r\n msg.sender,\r\n relayData.depositor,\r\n relayData.recipient,\r\n isSlowRelay\r\n );\r\n }\r\n\r\n function _emitDeposit(\r\n uint256 amount,\r\n uint256 originChainId,\r\n uint256 destinationChainId,\r\n uint64 relayerFeePct,\r\n uint32 depositId,\r\n uint32 quoteTimestamp,\r\n address originToken,\r\n address recipient,\r\n address depositor\r\n ) internal {\r\n emit FundsDeposited(\r\n amount,\r\n originChainId,\r\n destinationChainId,\r\n relayerFeePct,\r\n depositId,\r\n quoteTimestamp,\r\n originToken,\r\n recipient,\r\n depositor\r\n );\r\n }\r\n\r\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\r\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\r\n // L1, this would just be the same admin of the HubPool.\r\n function _requireAdminSender() internal virtual;\r\n\r\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\r\n receive() external payable {}\r\n}\r\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(wrappedNativeToken) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(wrappedNativeToken) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,40 +113,40 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-linecontract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {}\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {}\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/RateModelStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Maps rate model objects to L1 token.\n * @dev This contract is designed to be queried by off-chain relayers that need to compute realized LP fee %'s before\n * submitting relay transactions to a BridgePool contract. Therefore, this contract does not perform any validation on\n * the shape of the rate model, which is stored as a string to enable arbitrary data encoding via a stringified JSON\n * object. This leaves this contract unopionated on the parameters within the rate model, enabling governance to adjust\n * the structure in the future.\n */\ncontract RateModelStore is Ownable, MultiCaller {\n mapping(address => string) public l1TokenRateModels;\n\n event UpdatedRateModel(address indexed l1Token, string rateModel);\n\n /**\n * @notice Updates rate model string for L1 token.\n * @param l1Token the l1 token rate model to update.\n * @param rateModel the updated rate model.\n */\n function updateRateModel(address l1Token, string memory rateModel) external onlyOwner {\n l1TokenRateModels[l1Token] = rateModel;\n emit UpdatedRateModel(l1Token, rateModel);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -155,25 +155,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json b/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json index c017c42f..582dc2ea 100644 --- a/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json +++ b/deployments/rinkeby/solcInputs/2fe6c4b637a440a1380be3adbf7d9e12.json @@ -2,52 +2,52 @@ "language": "Solidity", "sources": { "contracts/HubPool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./HubPoolInterface.sol\";\nimport \"./Lockable.sol\";\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\nimport \"@uma/core/contracts/common/implementation/AncillaryData.sol\";\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\n\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\n * disabled by the admin.\n */\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\n // can be submitted.\n RootBundle public rootBundleProposal;\n\n // Whether the bundle proposal process is paused.\n bool public paused;\n\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\n mapping(bytes32 => address) private poolRebalanceRoutes;\n\n // Mapping of L1 token addresses to the associated pool information.\n mapping(address => PooledToken) public pooledTokens;\n\n // Mapping of chainId to the associated adapter and spokePool contracts.\n mapping(uint256 => CrossChainContract) public crossChainContracts;\n\n // WETH contract for Ethereum.\n WETH9 public immutable weth;\n\n // Helper factory to deploy new LP tokens for enabled L1 tokens\n LpTokenFactoryInterface public immutable lpTokenFactory;\n\n // Finder contract for this network.\n FinderInterface public immutable finder;\n\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\n\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\n // the full amount of fees entitled to LPs in ~ 7.72 days, just over the standard L2 7 day liveness.\n uint256 public lpFeeRatePerSecond = 1500000000000;\n\n // Mapping of l1TokenAddress to cumulative unclaimed protocol tokens that can be sent to the protocolFeeCaptureAddress\n // at any time. This enables the protocol to reallocate some percentage of LP fees elsewhere.\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\n\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\n address public protocolFeeCaptureAddress;\n\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\n uint256 public protocolFeeCapturePct;\n\n // Token used to bond the data worker for proposing relayer refund bundles.\n IERC20 public bondToken;\n\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\n uint256 public bondAmount;\n\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\n uint32 public liveness = 7200;\n\n event Paused(bool indexed isPaused);\n\n event EmergencyRootBundleDeleted(\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\n\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\n\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\n\n event LivenessSet(uint256 newLiveness);\n\n event IdentifierSet(bytes32 newIdentifier);\n\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\n\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\n\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\n\n event LiquidityAdded(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensMinted,\n address indexed liquidityProvider\n );\n event LiquidityRemoved(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensBurnt,\n address indexed liquidityProvider\n );\n event SetPoolRebalanceRoute(\n uint256 indexed destinationChainId,\n address indexed l1Token,\n address indexed destinationToken\n );\n event SetEnableDepositRoute(\n uint256 indexed originChainId,\n uint256 indexed destinationChainId,\n address indexed originToken,\n bool depositsEnabled\n );\n event ProposeRootBundle(\n uint32 requestExpirationTimestamp,\n uint64 unclaimedPoolRebalanceLeafCount,\n uint256[] bundleEvaluationBlockNumbers,\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n event RootBundleExecuted(\n uint256 groupIndex,\n uint256 indexed leafId,\n uint256 indexed chainId,\n address[] l1Token,\n uint256[] bundleLpFees,\n int256[] netSendAmount,\n int256[] runningBalance,\n address indexed caller\n );\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\n\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\n\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\n\n modifier noActiveRequests() {\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\n _;\n }\n\n modifier unpaused() {\n require(!paused, \"Proposal process has been paused\");\n _;\n }\n\n modifier zeroOptimisticOracleApproval() {\n _;\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\n }\n\n /**\n * @notice Construct HubPool.\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\n * @param _finder Finder address.\n * @param _weth WETH address.\n * @param _timer Timer address.\n */\n constructor(\n LpTokenFactoryInterface _lpTokenFactory,\n FinderInterface _finder,\n WETH9 _weth,\n address _timer\n ) Testable(_timer) {\n lpTokenFactory = _lpTokenFactory;\n finder = _finder;\n weth = _weth;\n protocolFeeCaptureAddress = owner();\n }\n\n /*************************************************\n * ADMIN FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function setPaused(bool pause) public onlyOwner nonReentrant {\n paused = pause;\n emit Paused(pause);\n }\n\n /**\n * @notice This allows for the deletion of the active proposal in case of emergency.\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\n */\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n emit EmergencyRootBundleDeleted(\n rootBundleProposal.poolRebalanceRoot,\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot,\n rootBundleProposal.proposer\n );\n delete rootBundleProposal;\n }\n\n /**\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\n * contract only allows the owner to call this method directly or indirectly.\n * @param chainId Chain with SpokePool to send message to.\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\n */\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\n public\n override\n onlyOwner\n nonReentrant\n {\n _relaySpokePoolAdminFunction(chainId, functionData);\n }\n\n /**\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\n * @param newProtocolFeeCapturePct New protocol fee capture %.\n */\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\n public\n override\n onlyOwner\n nonReentrant\n {\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\n protocolFeeCapturePct = newProtocolFeeCapturePct;\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\n }\n\n /**\n * @notice Sets bond token and amount. Callable only by owner.\n * @param newBondToken New bond currency.\n * @param newBondAmount New bond amount.\n */\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\n public\n override\n onlyOwner\n noActiveRequests\n nonReentrant\n {\n // Bond should not be great than final fee otherwise every proposal will get cancelled in a dispute.\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\n require(newBondAmount != 0, \"bond equal to final fee\");\n\n // Check that this token is on the whitelist.\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\n );\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\n\n // The bond should be the passed in bondAmount + the final fee.\n bondToken = newBondToken;\n bondAmount = newBondAmount + _getBondTokenFinalFee();\n emit BondSet(address(newBondToken), bondAmount);\n }\n\n /**\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\n * @param newLiveness New liveness period.\n */\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\n require(newLiveness > 10 minutes, \"Liveness too short\");\n liveness = newLiveness;\n emit LivenessSet(newLiveness);\n }\n\n /**\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\n * @param newIdentifier New identifier.\n */\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\n );\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\n identifier = newIdentifier;\n emit IdentifierSet(newIdentifier);\n }\n\n /**\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\n * @param l2ChainId Chain to set contracts for.\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\n */\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) public override onlyOwner nonReentrant {\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\n }\n\n /**\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\n * containing this l1 token + destination chain ID combination.\n * @param destinationChainId Destination chain where destination token resides.\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\n * destination chain ID.\n * @param destinationToken Destination chain counterpart of L1 token.\n */\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) public override onlyOwner nonReentrant {\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\n }\n\n /**\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\n * SpokePool to another one. Callable only by owner.\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\n * to the destination chain to refund the relayer.\n * @param originChainId Chain where token deposit occurs.\n * @param destinationChainId Chain where token depositor wants to receive funds.\n * @param originToken Token sent in deposit.\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\n */\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) public override nonReentrant onlyOwner {\n _relaySpokePoolAdminFunction(\n originChainId,\n abi.encodeWithSignature(\n \"setEnableRoute(address,uint256,bool)\",\n originToken,\n destinationChainId,\n depositsEnabled\n )\n );\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\n }\n\n /**\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\n * Callable only by owner.\n * @param l1Token Token to provide liquidity for.\n */\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\n if (pooledTokens[l1Token].lpToken == address(0)) {\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n pooledTokens[l1Token].isEnabled = true;\n\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /**\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\n * @param l1Token Token to disable liquidity provision for.\n */\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n pooledTokens[l1Token].isEnabled = false;\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /*************************************************\n * LIQUIDITY PROVIDER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\n * increments from the time that they enter the pool to reflect their accrued fees.\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\n * @param l1Token Token to deposit into this contract.\n * @param l1TokenAmount Amount of liquidity to provide.\n */\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\n // Else, msg.value must be set to 0.\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\n\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\n // first before transferring any tokens to this contract to ensure synchronization.\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\n\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\n\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\n }\n\n /**\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\n * @param l1Token Token to redeem LP share for.\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\n * via public exchangeRateCurrent method.\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\n * if this value is set to False, then the calling contract should have a way to handle WETH.\n */\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) public override nonReentrant {\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\n\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\n\n if (sendEth) {\n weth.withdraw(l1TokensToReturn);\n payable(msg.sender).transfer(l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\n } else {\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\n }\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\n }\n\n /**\n * @notice Returns exchange rate of L1 token to LP token.\n * @param l1Token L1 token redeemable by burning LP token.\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\n */\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _exchangeRateCurrent(l1Token);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\n * @param l1Token L1 token to query utilization for.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\n */\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _liquidityUtilizationPostRelay(l1Token, 0);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\n * relayedAmount of tokens to be withdrawn from the pool.\n * @param l1Token L1 token to query utilization for.\n * @param relayedAmount The higher this amount, the higher the utilization.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\n */\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\n public\n nonReentrant\n returns (uint256)\n {\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\n }\n\n /**\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\n */\n function sync(address l1Token) public override nonReentrant {\n _sync(l1Token);\n }\n\n /*************************************************\n * DATA WORKER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\n * called; moreover, this method can't be called again until all leaves are executed.\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\n * refund relayers on their chosen refund chainId.\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\n * fulfill slow relays.\n */\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) public override nonReentrant noActiveRequests unpaused {\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\n\n uint32 requestExpirationTimestamp = uint32(getCurrentTime()) + liveness;\n\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time.\n\n rootBundleProposal.requestExpirationTimestamp = requestExpirationTimestamp;\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\n rootBundleProposal.proposer = msg.sender;\n\n // Pull bondAmount of bondToken from the caller.\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n\n emit ProposeRootBundle(\n requestExpirationTimestamp,\n poolRebalanceLeafCount,\n bundleEvaluationBlockNumbers,\n poolRebalanceRoot,\n relayerRefundRoot,\n slowRelayRoot,\n msg.sender\n );\n }\n\n /**\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\n * relay roots to the SpokePool on the network specified in the leaf.\n * @dev In some cases, will instruct spokePool to send funds back to L1.\n * @notice Deletes the published root bundle if this is the last leaf to be executed in the root bundle.\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\n * @param leafId Index of this executed leaf within the poolRebalance tree.\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\n */\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) public nonReentrant unpaused {\n require(getCurrentTime() > rootBundleProposal.requestExpirationTimestamp, \"Not passed liveness\");\n\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\n\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\n require(\n MerkleLib.verifyPoolRebalance(\n rootBundleProposal.poolRebalanceRoot,\n PoolRebalanceLeaf({\n chainId: chainId,\n groupIndex: groupIndex,\n bundleLpFees: bundleLpFees,\n netSendAmounts: netSendAmounts,\n runningBalances: runningBalances,\n leafId: leafId,\n l1Tokens: l1Tokens\n }),\n proof\n ),\n \"Bad Proof\"\n );\n\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\n // is set improperly.\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Set the leafId in the claimed bitmap.\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\n\n // Decrement the unclaimedPoolRebalanceLeafCount.\n rootBundleProposal.unclaimedPoolRebalanceLeafCount--;\n\n // Relay each L1 token to destination chain.\n\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\n // then this internal method will revert. In this case the admin will have to associate a destination token\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\n // determine if the relayers used the correct destination token for a given origin token.\n _sendTokensToChainAndUpdatePooledTokenTrackers(\n adapter,\n spokePool,\n chainId,\n l1Tokens,\n netSendAmounts,\n bundleLpFees\n );\n\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\n if (groupIndex == 0) {\n // Relay root bundles to spoke pool on destination chain by\n // performing delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n abi.encodeWithSignature(\n \"relayRootBundle(bytes32,bytes32)\",\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot\n ) // message\n )\n );\n require(success, \"delegatecall failed\");\n }\n\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n\n emit RootBundleExecuted(\n groupIndex,\n leafId,\n chainId,\n l1Tokens,\n bundleLpFees,\n netSendAmounts,\n runningBalances,\n msg.sender\n );\n }\n\n /**\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\n */\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\n uint32 currentTime = uint32(getCurrentTime());\n require(currentTime <= rootBundleProposal.requestExpirationTimestamp, \"Request passed liveness\");\n\n // Request price from OO and dispute it.\n uint256 finalFee = _getBondTokenFinalFee();\n\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\n // data in this ancillary data that is already included in the ProposeRootBundle event.\n\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\n if (finalFee >= bondAmount) {\n _cancelBundle();\n return;\n }\n\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\n\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n try\n optimisticOracle.requestAndProposePriceFor(\n identifier,\n currentTime,\n \"\",\n bondToken,\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\n // proposal has passed the challenge period.\n 0,\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\n bondAmount - finalFee,\n // Set the Optimistic oracle liveness for the price request.\n liveness,\n rootBundleProposal.proposer,\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\n int256(1e18)\n )\n returns (uint256) {\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\n // to transfer than intended.\n bondToken.safeApprove(address(optimisticOracle), 0);\n } catch {\n // Cancel the bundle since the proposal failed.\n _cancelBundle();\n return;\n }\n\n // Dispute the request that we just sent.\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\n proposer: rootBundleProposal.proposer,\n disputer: address(0),\n currency: bondToken,\n settled: false,\n proposedPrice: int256(1e18),\n resolvedPrice: 0,\n expirationTime: currentTime + liveness,\n reward: 0,\n finalFee: finalFee,\n bond: bondAmount - finalFee,\n customLiveness: liveness\n });\n\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\n delete rootBundleProposal;\n\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\n\n emit RootBundleDisputed(msg.sender, currentTime);\n }\n\n /**\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\n * @param l1Token Token whose protocol fees the caller wants to disburse.\n */\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\n }\n\n /**\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\n * @param destinationChainId Where destination token is deployed.\n * @param l1Token Ethereum version token.\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\n * the l1Token to the destination chain.\n */\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n override\n returns (address destinationToken)\n {\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\n }\n\n /**\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\n * Arbitrum calls, but may also be needed for others.\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\n */\n function loadEthForL2Calls() public payable override {}\n\n /*************************************************\n * INTERNAL FUNCTIONS *\n *************************************************/\n\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\n // with no loss of funds, thereby enabling a new bundle to be added.\n function _cancelBundle() internal {\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\n delete rootBundleProposal;\n emit RootBundleCanceled(msg.sender, getCurrentTime());\n }\n\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\n return\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\n }\n\n function _getBondTokenFinalFee() internal view returns (uint256) {\n return\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\n .computeFinalFee(address(bondToken))\n .rawValue;\n }\n\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\n address adapter,\n address spokePool,\n uint256 chainId,\n address[] memory l1Tokens,\n int256[] memory netSendAmounts,\n uint256[] memory bundleLpFees\n ) internal {\n for (uint32 i = 0; i < l1Tokens.length; i++) {\n address l1Token = l1Tokens[i];\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\n // could send tokens to the 0x0 address on the L2.\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\n require(l2Token != address(0), \"Route not whitelisted\");\n\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\n if (netSendAmounts[i] > 0) {\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\n // complexity in exchange for lower gas costs.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayTokens(address,address,uint256,address)\",\n l1Token, // l1Token.\n l2Token, // l2Token.\n uint256(netSendAmounts[i]), // amount.\n spokePool // to. This should be the spokePool.\n )\n );\n require(success, \"delegatecall failed\");\n\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\n }\n\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\n }\n }\n\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\n\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\n // gradually increase over time as undistributedLpFees goes to zero.\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\n // int will always be positive so there is no risk in underflow in type casting in the return line.\n int256 numerator = int256(pooledToken.liquidReserves) +\n pooledToken.utilizedReserves -\n int256(pooledToken.undistributedLpFees);\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\n }\n\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\n pooledToken.undistributedLpFees -= accumulatedFees;\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\n }\n\n function _sync(address l1Token) internal {\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\n // action from L2 -> L1 has concluded and the local accounting can be updated.\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\n // active request.\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\n // dropped onto the contract, exceeding the liquidReserves.\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\n }\n }\n\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\n PooledToken memory pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 flooredUtilizedReserves = pooledToken.utilizedReserves > 0 ? uint256(pooledToken.utilizedReserves) : 0;\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\n uint256 denominator = pooledToken.liquidReserves + flooredUtilizedReserves;\n\n // If the denominator equals zero, return 1e18 (max utilization).\n if (denominator == 0) return 1e18;\n\n // In all other cases, return the utilization ratio.\n return (numerator * 1e18) / denominator;\n }\n\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\n\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\n if (lpFeesCaptured > 0) {\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\n }\n\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\n }\n\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Perform delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n functionData\n )\n );\n require(success, \"delegatecall failed\");\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\n }\n\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\n return keccak256(abi.encode(l1Token, destinationChainId));\n }\n\n function _getInitializedCrossChainContracts(uint256 chainId)\n internal\n view\n returns (address adapter, address spokePool)\n {\n adapter = crossChainContracts[chainId].adapter;\n spokePool = crossChainContracts[chainId].spokePool;\n require(spokePool != address(0), \"SpokePool not initialized\");\n require(adapter.isContract(), \"Adapter not initialized\");\n }\n\n function _activeRequest() internal view returns (bool) {\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\n }\n\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\n function _depositEthToWeth() internal {\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\n }\n\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\n fallback() external payable {\n _depositEthToWeth();\n }\n\n receive() external payable {\n _depositEthToWeth();\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./HubPoolInterface.sol\";\nimport \"./Lockable.sol\";\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@uma/core/contracts/oracle/implementation/Constants.sol\";\nimport \"@uma/core/contracts/common/implementation/AncillaryData.sol\";\nimport \"@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol\";\n\nimport \"@uma/core/contracts/oracle/interfaces/FinderInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/StoreInterface.sol\";\nimport \"@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol\";\nimport \"@uma/core/contracts/common/interfaces/ExpandedIERC20.sol\";\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools. A dataworker can interact\n * with merkle roots stored in this contract via inclusion proofs to instruct this contract to send tokens to L2\n * SpokePools via \"pool rebalances\" that can be used to pay out relayers on those networks. This contract is also\n * responsible for publishing relayer refund and slow relay merkle roots to SpokePools.\n * @notice This contract is meant to act as the cross chain administrator and owner of all L2 spoke pools, so all\n * governance actions and pool rebalances originate from here and bridge instructions to L2s.\n * @dev This contract should be deprecated by the year 2106, at which point uint32 timestamps will roll over. This is\n * an issue for this contract because fee calculations will become bizarre when multiplying by negative time deltas.\n * Before this date, this contract should be paused from accepting new root bundles and all LP tokens should be\n * disabled by the admin.\n */\ncontract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Only one root bundle can be stored at a time. Once all pool rebalance leaves are executed, a new proposal\n // can be submitted.\n RootBundle public rootBundleProposal;\n\n // Whether the bundle proposal process is paused.\n bool public paused;\n\n // Stores paths from L1 token + destination ID to destination token. Since different tokens on L1 might map to\n // to the same address on different destinations, we hash (L1 token address, destination ID) to\n // use as a key that maps to a destination token. This mapping is used to direct pool rebalances from\n // HubPool to SpokePool, and also is designed to be used as a lookup for off-chain data workers to determine\n // which L1 tokens to relay to SpokePools to refund relayers. The admin can set the \"destination token\"\n // to 0x0 to disable a pool rebalance route and block executeRootBundle() from executing.\n mapping(bytes32 => address) private poolRebalanceRoutes;\n\n // Mapping of L1 token addresses to the associated pool information.\n mapping(address => PooledToken) public pooledTokens;\n\n // Mapping of chainId to the associated adapter and spokePool contracts.\n mapping(uint256 => CrossChainContract) public crossChainContracts;\n\n // WETH contract for Ethereum.\n WETH9 public immutable weth;\n\n // Helper factory to deploy new LP tokens for enabled L1 tokens\n LpTokenFactoryInterface public immutable lpTokenFactory;\n\n // Finder contract for this network.\n FinderInterface public immutable finder;\n\n // When root bundles are disputed a price request is enqueued with the DVM to resolve the resolution.\n bytes32 public identifier = \"IS_ACROSS_V2_BUNDLE_VALID\";\n\n // Interest rate payment that scales the amount of pending fees per second paid to LPs. 0.0000015e18 will pay out\n // the full amount of fees entitled to LPs in ~ 7.72 days, just over the standard L2 7 day liveness.\n uint256 public lpFeeRatePerSecond = 1500000000000;\n\n // Mapping of l1TokenAddress to cumulative unclaimed protocol tokens that can be sent to the protocolFeeCaptureAddress\n // at any time. This enables the protocol to reallocate some percentage of LP fees elsewhere.\n mapping(address => uint256) public unclaimedAccumulatedProtocolFees;\n\n // Address that captures protocol fees. Accumulated protocol fees can be claimed by this address.\n address public protocolFeeCaptureAddress;\n\n // Percentage of lpFees that are captured by the protocol and claimable by the protocolFeeCaptureAddress.\n uint256 public protocolFeeCapturePct;\n\n // Token used to bond the data worker for proposing relayer refund bundles.\n IERC20 public bondToken;\n\n // The computed bond amount as the UMA Store's final fee multiplied by the bondTokenFinalFeeMultiplier.\n uint256 public bondAmount;\n\n // Each root bundle proposal must stay in liveness for this period of time before it can be considered finalized.\n // It can be disputed only during this period of time. Defaults to 2 hours, like the rest of the UMA ecosystem.\n uint32 public liveness = 7200;\n\n event Paused(bool indexed isPaused);\n\n event EmergencyRootBundleDeleted(\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n\n event ProtocolFeeCaptureSet(address indexed newProtocolFeeCaptureAddress, uint256 indexed newProtocolFeeCapturePct);\n\n event ProtocolFeesCapturedClaimed(address indexed l1Token, uint256 indexed accumulatedFees);\n\n event BondSet(address indexed newBondToken, uint256 newBondAmount);\n\n event LivenessSet(uint256 newLiveness);\n\n event IdentifierSet(bytes32 newIdentifier);\n\n event CrossChainContractsSet(uint256 l2ChainId, address adapter, address spokePool);\n\n event L1TokenEnabledForLiquidityProvision(address l1Token, address lpToken);\n\n event L2TokenDisabledForLiquidityProvision(address l1Token, address lpToken);\n\n event LiquidityAdded(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensMinted,\n address indexed liquidityProvider\n );\n event LiquidityRemoved(\n address indexed l1Token,\n uint256 amount,\n uint256 lpTokensBurnt,\n address indexed liquidityProvider\n );\n event SetPoolRebalanceRoute(\n uint256 indexed destinationChainId,\n address indexed l1Token,\n address indexed destinationToken\n );\n event SetEnableDepositRoute(\n uint256 indexed originChainId,\n uint256 indexed destinationChainId,\n address indexed originToken,\n bool depositsEnabled\n );\n event ProposeRootBundle(\n uint32 requestExpirationTimestamp,\n uint64 unclaimedPoolRebalanceLeafCount,\n uint256[] bundleEvaluationBlockNumbers,\n bytes32 indexed poolRebalanceRoot,\n bytes32 indexed relayerRefundRoot,\n bytes32 slowRelayRoot,\n address indexed proposer\n );\n event RootBundleExecuted(\n uint256 groupIndex,\n uint256 indexed leafId,\n uint256 indexed chainId,\n address[] l1Token,\n uint256[] bundleLpFees,\n int256[] netSendAmount,\n int256[] runningBalance,\n address indexed caller\n );\n event SpokePoolAdminFunctionTriggered(uint256 indexed chainId, bytes message);\n\n event RootBundleDisputed(address indexed disputer, uint256 requestTime);\n\n event RootBundleCanceled(address indexed disputer, uint256 requestTime);\n\n modifier noActiveRequests() {\n require(!_activeRequest(), \"Proposal has unclaimed leaves\");\n _;\n }\n\n modifier unpaused() {\n require(!paused, \"Proposal process has been paused\");\n _;\n }\n\n modifier zeroOptimisticOracleApproval() {\n _;\n bondToken.safeApprove(address(_getOptimisticOracle()), 0);\n }\n\n /**\n * @notice Construct HubPool.\n * @param _lpTokenFactory LP Token factory address used to deploy LP tokens for new collateral types.\n * @param _finder Finder address.\n * @param _weth WETH address.\n * @param _timer Timer address.\n */\n constructor(\n LpTokenFactoryInterface _lpTokenFactory,\n FinderInterface _finder,\n WETH9 _weth,\n address _timer\n ) Testable(_timer) {\n lpTokenFactory = _lpTokenFactory;\n finder = _finder;\n weth = _weth;\n protocolFeeCaptureAddress = owner();\n }\n\n /*************************************************\n * ADMIN FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Pauses the bundle proposal and execution process. This is intended to be used during upgrades or when\n * something goes awry.\n * @param pause true if the call is meant to pause the system, false if the call is meant to unpause it.\n */\n function setPaused(bool pause) public onlyOwner nonReentrant {\n paused = pause;\n emit Paused(pause);\n }\n\n /**\n * @notice This allows for the deletion of the active proposal in case of emergency.\n * @dev This is primarily intended to rectify situations where an unexecutable bundle gets through liveness in the\n * case of a non-malicious bug in the proposal/dispute code. Without this function, the contract would be\n * indefinitely blocked, migration would be required, and in-progress transfers would never be repaid.\n */\n function emergencyDeleteProposal() public onlyOwner nonReentrant {\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount > 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n emit EmergencyRootBundleDeleted(\n rootBundleProposal.poolRebalanceRoot,\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot,\n rootBundleProposal.proposer\n );\n delete rootBundleProposal;\n }\n\n /**\n * @notice Sends message to SpokePool from this contract. Callable only by owner.\n * @dev This function has permission to call onlyAdmin functions on the SpokePool, so it's imperative that this\n * contract only allows the owner to call this method directly or indirectly.\n * @param chainId Chain with SpokePool to send message to.\n * @param functionData ABI encoded function call to send to SpokePool, but can be any arbitrary data technically.\n */\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData)\n public\n override\n onlyOwner\n nonReentrant\n {\n _relaySpokePoolAdminFunction(chainId, functionData);\n }\n\n /**\n * @notice Sets protocolFeeCaptureAddress and protocolFeeCapturePct. Callable only by owner.\n * @param newProtocolFeeCaptureAddress New protocol fee capture address.\n * @param newProtocolFeeCapturePct New protocol fee capture %.\n */\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct)\n public\n override\n onlyOwner\n nonReentrant\n {\n require(newProtocolFeeCapturePct <= 1e18, \"Bad protocolFeeCapturePct\");\n require(newProtocolFeeCaptureAddress != address(0), \"Bad protocolFeeCaptureAddress\");\n protocolFeeCaptureAddress = newProtocolFeeCaptureAddress;\n protocolFeeCapturePct = newProtocolFeeCapturePct;\n emit ProtocolFeeCaptureSet(newProtocolFeeCaptureAddress, newProtocolFeeCapturePct);\n }\n\n /**\n * @notice Sets bond token and amount. Callable only by owner.\n * @param newBondToken New bond currency.\n * @param newBondAmount New bond amount.\n */\n function setBond(IERC20 newBondToken, uint256 newBondAmount)\n public\n override\n onlyOwner\n noActiveRequests\n nonReentrant\n {\n // Bond should not be great than final fee otherwise every proposal will get cancelled in a dispute.\n // In practice we expect that bond amounts are set >> final fees so this shouldn't be an inconvenience.\n // The only way for the bond amount to be equal to the final fee is if the newBondAmount == 0.\n require(newBondAmount != 0, \"bond equal to final fee\");\n\n // Check that this token is on the whitelist.\n AddressWhitelistInterface addressWhitelist = AddressWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)\n );\n require(addressWhitelist.isOnWhitelist(address(newBondToken)), \"Not on whitelist\");\n\n // The bond should be the passed in bondAmount + the final fee.\n bondToken = newBondToken;\n bondAmount = newBondAmount + _getBondTokenFinalFee();\n emit BondSet(address(newBondToken), bondAmount);\n }\n\n /**\n * @notice Sets root bundle proposal liveness period. Callable only by owner.\n * @param newLiveness New liveness period.\n */\n function setLiveness(uint32 newLiveness) public override onlyOwner nonReentrant {\n require(newLiveness > 10 minutes, \"Liveness too short\");\n liveness = newLiveness;\n emit LivenessSet(newLiveness);\n }\n\n /**\n * @notice Sets identifier for root bundle disputes. Callable only by owner.\n * @param newIdentifier New identifier.\n */\n function setIdentifier(bytes32 newIdentifier) public override onlyOwner noActiveRequests nonReentrant {\n IdentifierWhitelistInterface identifierWhitelist = IdentifierWhitelistInterface(\n finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)\n );\n require(identifierWhitelist.isIdentifierSupported(newIdentifier), \"Identifier not supported\");\n identifier = newIdentifier;\n emit IdentifierSet(newIdentifier);\n }\n\n /**\n * @notice Sets cross chain relay helper contracts for L2 chain ID. Callable only by owner.\n * @dev We do not block setting the adapter or SpokePool to invalid/zero addresses because we want to allow the\n * admin to block relaying roots to the spoke pool for emergency recovery purposes.\n * @param l2ChainId Chain to set contracts for.\n * @param adapter Adapter used to relay messages and tokens to spoke pool. Deployed on current chain.\n * @param spokePool Recipient of relayed messages and tokens on spoke pool. Deployed on l2ChainId.\n */\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) public override onlyOwner nonReentrant {\n crossChainContracts[l2ChainId] = CrossChainContract(adapter, spokePool);\n emit CrossChainContractsSet(l2ChainId, adapter, spokePool);\n }\n\n /**\n * @notice Store canonical destination token counterpart for l1 token. Callable only by owner.\n * @dev Admin can set destinationToken to 0x0 to effectively disable executing any root bundles with leaves\n * containing this l1 token + destination chain ID combination.\n * @param destinationChainId Destination chain where destination token resides.\n * @param l1Token Token enabled for liquidity in this pool, and the L1 counterpart to the destination token on the\n * destination chain ID.\n * @param destinationToken Destination chain counterpart of L1 token.\n */\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) public override onlyOwner nonReentrant {\n poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)] = destinationToken;\n emit SetPoolRebalanceRoute(destinationChainId, l1Token, destinationToken);\n }\n\n /**\n * @notice Sends cross-chain message to SpokePool on originChainId to enable or disable deposit route from that\n * SpokePool to another one. Callable only by owner.\n * @dev Admin is responsible for ensuring that `originToken` is linked to some L1 token on this contract, via\n * poolRebalanceRoutes(), and that this L1 token also has a counterpart on the destination chain. If either\n * condition fails, then the deposit will be unrelayable by off-chain relayers because they will not know which\n * token to relay to recipients on the destination chain, and data workers wouldn't know which L1 token to send\n * to the destination chain to refund the relayer.\n * @param originChainId Chain where token deposit occurs.\n * @param destinationChainId Chain where token depositor wants to receive funds.\n * @param originToken Token sent in deposit.\n * @param depositsEnabled Set to true to whitelist this route for deposits, set to false if caller just wants to\n * map the origin token + destination ID to the destination token address on the origin chain's SpokePool.\n */\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) public override nonReentrant onlyOwner {\n _relaySpokePoolAdminFunction(\n originChainId,\n abi.encodeWithSignature(\n \"setEnableRoute(address,uint256,bool)\",\n originToken,\n destinationChainId,\n depositsEnabled\n )\n );\n emit SetEnableDepositRoute(originChainId, destinationChainId, originToken, depositsEnabled);\n }\n\n /**\n * @notice Enables LPs to provide liquidity for L1 token. Deploys new LP token for L1 token if appropriate.\n * Callable only by owner.\n * @param l1Token Token to provide liquidity for.\n */\n function enableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n // If token is being enabled for the first time, create a new LP token and set the timestamp once. We don't\n // want to ever reset this timestamp otherwise fees that have accrued will be lost since the last update. This\n // could happen for example if an L1 token is enabled, disabled, and then enabled again.\n if (pooledTokens[l1Token].lpToken == address(0)) {\n pooledTokens[l1Token].lpToken = lpTokenFactory.createLpToken(l1Token);\n pooledTokens[l1Token].lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n pooledTokens[l1Token].isEnabled = true;\n\n emit L1TokenEnabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /**\n * @notice Disables LPs from providing liquidity for L1 token. Callable only by owner.\n * @param l1Token Token to disable liquidity provision for.\n */\n function disableL1TokenForLiquidityProvision(address l1Token) public override onlyOwner nonReentrant {\n pooledTokens[l1Token].isEnabled = false;\n emit L2TokenDisabledForLiquidityProvision(l1Token, pooledTokens[l1Token].lpToken);\n }\n\n /*************************************************\n * LIQUIDITY PROVIDER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Deposit liquidity into this contract to earn LP fees in exchange for funding relays on SpokePools.\n * Caller is essentially loaning their funds to be sent from this contract to the SpokePool, where it will be used\n * to repay a relayer, and ultimately receives their loan back after the tokens are bridged back to this contract\n * via the canonical token bridge. Then, the caller's loans are used again. This loan cycle repeats continuously\n * and the caller, or \"liquidity provider\" earns a continuous fee for their credit that they are extending relayers.\n * @notice Caller will receive an LP token representing their share of this pool. The LP token's redemption value\n * increments from the time that they enter the pool to reflect their accrued fees.\n * @notice The caller of this function must approve this contract to spend l1TokenAmount of l1Token.\n * @param l1Token Token to deposit into this contract.\n * @param l1TokenAmount Amount of liquidity to provide.\n */\n function addLiquidity(address l1Token, uint256 l1TokenAmount) public payable override nonReentrant {\n require(pooledTokens[l1Token].isEnabled, \"Token not enabled\");\n // If this is the weth pool and the caller sends msg.value then the msg.value must match the l1TokenAmount.\n // Else, msg.value must be set to 0.\n require(((address(weth) == l1Token) && msg.value == l1TokenAmount) || msg.value == 0, \"Bad msg.value\");\n\n // Since _exchangeRateCurrent() reads this contract's balance and updates contract state using it, it must be\n // first before transferring any tokens to this contract to ensure synchronization.\n uint256 lpTokensToMint = (l1TokenAmount * 1e18) / _exchangeRateCurrent(l1Token);\n pooledTokens[l1Token].liquidReserves += l1TokenAmount;\n ExpandedIERC20(pooledTokens[l1Token].lpToken).mint(msg.sender, lpTokensToMint);\n\n if (address(weth) == l1Token && msg.value > 0) WETH9(address(l1Token)).deposit{ value: msg.value }();\n else IERC20(l1Token).safeTransferFrom(msg.sender, address(this), l1TokenAmount);\n\n emit LiquidityAdded(l1Token, l1TokenAmount, lpTokensToMint, msg.sender);\n }\n\n /**\n * @notice Burns LP share to redeem for underlying l1Token original deposit amount plus fees.\n * @param l1Token Token to redeem LP share for.\n * @param lpTokenAmount Amount of LP tokens to burn. Exchange rate between L1 token and LP token can be queried\n * via public exchangeRateCurrent method.\n * @param sendEth Set to True if L1 token is WETH and user wants to receive ETH. Note that if caller\n * is a contract, then the contract should have a way to receive ETH if this value is set to True. Similarly,\n * if this value is set to False, then the calling contract should have a way to handle WETH.\n */\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) public override nonReentrant {\n require(address(weth) == l1Token || !sendEth, \"Cant send eth\");\n uint256 l1TokensToReturn = (lpTokenAmount * _exchangeRateCurrent(l1Token)) / 1e18;\n\n ExpandedIERC20(pooledTokens[l1Token].lpToken).burnFrom(msg.sender, lpTokenAmount);\n // Note this method does not make any liquidity utilization checks before letting the LP redeem their LP tokens.\n // If they try access more funds than available (i.e l1TokensToReturn > liquidReserves) this will underflow.\n pooledTokens[l1Token].liquidReserves -= l1TokensToReturn;\n\n if (sendEth) {\n weth.withdraw(l1TokensToReturn);\n payable(msg.sender).transfer(l1TokensToReturn); // This will revert if the caller is a contract that does not implement a fallback function.\n } else {\n IERC20(address(l1Token)).safeTransfer(msg.sender, l1TokensToReturn);\n }\n emit LiquidityRemoved(l1Token, l1TokensToReturn, lpTokenAmount, msg.sender);\n }\n\n /**\n * @notice Returns exchange rate of L1 token to LP token.\n * @param l1Token L1 token redeemable by burning LP token.\n * @return Amount of L1 tokens redeemable for 1 unit LP token.\n */\n function exchangeRateCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _exchangeRateCurrent(l1Token);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools.\n * @param l1Token L1 token to query utilization for.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools.\n */\n function liquidityUtilizationCurrent(address l1Token) public override nonReentrant returns (uint256) {\n return _liquidityUtilizationPostRelay(l1Token, 0);\n }\n\n /**\n * @notice Returns % of liquid reserves currently being \"used\" and sitting in SpokePools and accounting for\n * relayedAmount of tokens to be withdrawn from the pool.\n * @param l1Token L1 token to query utilization for.\n * @param relayedAmount The higher this amount, the higher the utilization.\n * @return % of liquid reserves currently being \"used\" and sitting in SpokePools plus the relayedAmount.\n */\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount)\n public\n nonReentrant\n returns (uint256)\n {\n return _liquidityUtilizationPostRelay(l1Token, relayedAmount);\n }\n\n /**\n * @notice Synchronize any balance changes in this contract with the utilized & liquid reserves. This should be done\n * at the conclusion of a L2->L1 token transfer via the canonical token bridge, when this contract's reserves do not\n * reflect its true balance due to new tokens being dropped onto the contract at the conclusion of a bridging action.\n */\n function sync(address l1Token) public override nonReentrant {\n _sync(l1Token);\n }\n\n /*************************************************\n * DATA WORKER FUNCTIONS *\n *************************************************/\n\n /**\n * @notice Publish a new root bundle along with all of the block numbers that the merkle roots are relevant for.\n * This is used to aid off-chain validators in evaluating the correctness of this bundle. Caller stakes a bond that\n * can be slashed if the root bundle proposal is invalid, and they will receive it back if accepted.\n * @notice After proposeRootBundle is called, if the any props are wrong then this proposal can be challenged.\n * Once the challenge period passes, then the roots are no longer disputable, and only executeRootBundle can be\n * called; moreover, this method can't be called again until all leaves are executed.\n * @param bundleEvaluationBlockNumbers should contain the latest block number for all chains, even if there are no\n * relays contained on some of them. The usage of this variable should be defined in an off chain UMIP.\n * @notice The caller of this function must approve this contract to spend bondAmount of bondToken.\n * @param poolRebalanceLeafCount Number of leaves contained in pool rebalance root. Max is # of whitelisted chains.\n * @param poolRebalanceRoot Pool rebalance root containing leaves that sends tokens from this contract to SpokePool.\n * @param relayerRefundRoot Relayer refund root to publish to SpokePool where a data worker can execute leaves to\n * refund relayers on their chosen refund chainId.\n * @param slowRelayRoot Slow relay root to publish to Spoke Pool where a data worker can execute leaves to\n * fulfill slow relays.\n */\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) public override nonReentrant noActiveRequests unpaused {\n // Note: this is to prevent \"empty block\" style attacks where someone can make empty proposals that are\n // technically valid but not useful. This could also potentially be enforced at the UMIP-level.\n require(poolRebalanceLeafCount > 0, \"Bundle must have at least 1 leaf\");\n\n uint32 requestExpirationTimestamp = uint32(getCurrentTime()) + liveness;\n\n delete rootBundleProposal; // Only one bundle of roots can be executed at a time.\n\n rootBundleProposal.requestExpirationTimestamp = requestExpirationTimestamp;\n rootBundleProposal.unclaimedPoolRebalanceLeafCount = poolRebalanceLeafCount;\n rootBundleProposal.poolRebalanceRoot = poolRebalanceRoot;\n rootBundleProposal.relayerRefundRoot = relayerRefundRoot;\n rootBundleProposal.slowRelayRoot = slowRelayRoot;\n rootBundleProposal.proposer = msg.sender;\n\n // Pull bondAmount of bondToken from the caller.\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n\n emit ProposeRootBundle(\n requestExpirationTimestamp,\n poolRebalanceLeafCount,\n bundleEvaluationBlockNumbers,\n poolRebalanceRoot,\n relayerRefundRoot,\n slowRelayRoot,\n msg.sender\n );\n }\n\n /**\n * @notice Executes a pool rebalance leaf as part of the currently published root bundle. Will bridge any tokens\n * from this contract to the SpokePool designated in the leaf, and will also publish relayer refund and slow\n * relay roots to the SpokePool on the network specified in the leaf.\n * @dev In some cases, will instruct spokePool to send funds back to L1.\n * @notice Deletes the published root bundle if this is the last leaf to be executed in the root bundle.\n * @param chainId ChainId number of the target spoke pool on which the bundle is executed.\n * @param groupIndex If set to 0, then relay roots to SpokePool via cross chain bridge. Used by off-chain validator\n * to organize leaves with the same chain ID and also set which leaves should result in relayed messages.\n * @param bundleLpFees Array representing the total LP fee amount per token in this bundle for all bundled relays.\n * @param netSendAmounts Array representing the amount of tokens to send to the SpokePool on the target chainId.\n * @param runningBalances Array used to track any unsent tokens that are not included in the netSendAmounts.\n * @param leafId Index of this executed leaf within the poolRebalance tree.\n * @param l1Tokens Array of all the tokens associated with the bundleLpFees, nedSendAmounts and runningBalances.\n * @param proof Inclusion proof for this leaf in pool rebalance root in root bundle.\n */\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) public nonReentrant unpaused {\n require(getCurrentTime() > rootBundleProposal.requestExpirationTimestamp, \"Not passed liveness\");\n\n // Verify the leafId in the poolRebalanceLeaf has not yet been claimed.\n require(!MerkleLib.isClaimed1D(rootBundleProposal.claimedBitMap, leafId), \"Already claimed\");\n\n // Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.\n require(\n MerkleLib.verifyPoolRebalance(\n rootBundleProposal.poolRebalanceRoot,\n PoolRebalanceLeaf({\n chainId: chainId,\n groupIndex: groupIndex,\n bundleLpFees: bundleLpFees,\n netSendAmounts: netSendAmounts,\n runningBalances: runningBalances,\n leafId: leafId,\n l1Tokens: l1Tokens\n }),\n proof\n ),\n \"Bad Proof\"\n );\n\n // Get cross chain helpers for leaf's destination chain ID. This internal method will revert if either helper\n // is set improperly.\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Set the leafId in the claimed bitmap.\n rootBundleProposal.claimedBitMap = MerkleLib.setClaimed1D(rootBundleProposal.claimedBitMap, leafId);\n\n // Decrement the unclaimedPoolRebalanceLeafCount.\n rootBundleProposal.unclaimedPoolRebalanceLeafCount--;\n\n // Relay each L1 token to destination chain.\n\n // Note: if any of the keccak256(l1Tokens, chainId) combinations are not mapped to a destination token address,\n // then this internal method will revert. In this case the admin will have to associate a destination token\n // with each l1 token. If the destination token mapping was missing at the time of the proposal, we assume\n // that the root bundle would have been disputed because the off-chain data worker would have been unable to\n // determine if the relayers used the correct destination token for a given origin token.\n _sendTokensToChainAndUpdatePooledTokenTrackers(\n adapter,\n spokePool,\n chainId,\n l1Tokens,\n netSendAmounts,\n bundleLpFees\n );\n\n // Check bool used by data worker to prevent relaying redundant roots to SpokePool.\n if (groupIndex == 0) {\n // Relay root bundles to spoke pool on destination chain by\n // performing delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n abi.encodeWithSignature(\n \"relayRootBundle(bytes32,bytes32)\",\n rootBundleProposal.relayerRefundRoot,\n rootBundleProposal.slowRelayRoot\n ) // message\n )\n );\n require(success, \"delegatecall failed\");\n }\n\n // Transfer the bondAmount back to the proposer, if this the last executed leaf. Only sending this once all\n // leaves have been executed acts to force the data worker to execute all bundles or they won't receive their bond.\n if (rootBundleProposal.unclaimedPoolRebalanceLeafCount == 0)\n bondToken.safeTransfer(rootBundleProposal.proposer, bondAmount);\n\n emit RootBundleExecuted(\n groupIndex,\n leafId,\n chainId,\n l1Tokens,\n bundleLpFees,\n netSendAmounts,\n runningBalances,\n msg.sender\n );\n }\n\n /**\n * @notice Caller stakes a bond to dispute the current root bundle proposal assuming it has not passed liveness\n * yet. The proposal is deleted, allowing a follow-up proposal to be submitted, and the dispute is sent to the\n * optimistic oracle to be adjudicated. Can only be called within the liveness period of the current proposal.\n * @notice The caller of this function must approve this contract to spend bondAmount of l1Token.\n */\n function disputeRootBundle() public nonReentrant zeroOptimisticOracleApproval {\n uint32 currentTime = uint32(getCurrentTime());\n require(currentTime <= rootBundleProposal.requestExpirationTimestamp, \"Request passed liveness\");\n\n // Request price from OO and dispute it.\n uint256 finalFee = _getBondTokenFinalFee();\n\n // This method will request a price from the OO and dispute it. Note that we set the ancillary data to\n // the empty string (\"\"). The root bundle that is being disputed was the most recently proposed one with a\n // block number less than or equal to the dispute block time. All of this root bundle data can be found in\n // the ProposeRootBundle event params. Moreover, the optimistic oracle will stamp the requester's address\n // (i.e. this contract address) meaning that ancillary data for a dispute originating from another HubPool\n // will always be distinct from a dispute originating from this HubPool. Moreover, since\n // bundleEvaluationNumbers for a root bundle proposal are not stored in this contract, DVM voters will always\n // have to look up the ProposeRootBundle event to evaluate a dispute, therefore there is no point emitting extra\n // data in this ancillary data that is already included in the ProposeRootBundle event.\n\n // If the finalFee is larger than the bond amount, the bond amount needs to be reset before a request can go\n // through. Cancel to avoid a revert. Similarly, if the final fee == bond amount, then the proposer bond\n // set in the optimistic oracle would be 0. The optimistic oracle would then default the bond to be equal\n // to the final fee, which would mean that the allowance set to the bondAmount would be insufficient and the\n // requestAndProposePriceFor() call would revert. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L321\n if (finalFee >= bondAmount) {\n _cancelBundle();\n return;\n }\n\n SkinnyOptimisticOracleInterface optimisticOracle = _getOptimisticOracle();\n\n // Only approve exact tokens to avoid more tokens than expected being pulled into the OptimisticOracle.\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n try\n optimisticOracle.requestAndProposePriceFor(\n identifier,\n currentTime,\n \"\",\n bondToken,\n // Set reward to 0, since we'll settle proposer reward payouts directly from this contract after a root\n // proposal has passed the challenge period.\n 0,\n // Set the Optimistic oracle proposer bond for the request. We can assume that bondAmount > finalFee.\n bondAmount - finalFee,\n // Set the Optimistic oracle liveness for the price request.\n liveness,\n rootBundleProposal.proposer,\n // Canonical value representing \"True\"; i.e. the proposed relay is valid.\n int256(1e18)\n )\n returns (uint256) {\n // Ensure that approval == 0 after the call so the increaseAllowance call below doesn't allow more tokens\n // to transfer than intended.\n bondToken.safeApprove(address(optimisticOracle), 0);\n } catch {\n // Cancel the bundle since the proposal failed.\n _cancelBundle();\n return;\n }\n\n // Dispute the request that we just sent.\n SkinnyOptimisticOracleInterface.Request memory ooPriceRequest = SkinnyOptimisticOracleInterface.Request({\n proposer: rootBundleProposal.proposer,\n disputer: address(0),\n currency: bondToken,\n settled: false,\n proposedPrice: int256(1e18),\n resolvedPrice: 0,\n expirationTime: currentTime + liveness,\n reward: 0,\n finalFee: finalFee,\n bond: bondAmount - finalFee,\n customLiveness: liveness\n });\n\n // Finally, delete the state pertaining to the active proposal so that another proposer can submit a new bundle.\n delete rootBundleProposal;\n\n bondToken.safeTransferFrom(msg.sender, address(this), bondAmount);\n bondToken.safeIncreaseAllowance(address(optimisticOracle), bondAmount);\n optimisticOracle.disputePriceFor(identifier, currentTime, \"\", ooPriceRequest, msg.sender, address(this));\n\n emit RootBundleDisputed(msg.sender, currentTime);\n }\n\n /**\n * @notice Send unclaimed accumulated protocol fees to fee capture address.\n * @param l1Token Token whose protocol fees the caller wants to disburse.\n */\n function claimProtocolFeesCaptured(address l1Token) public override nonReentrant {\n uint256 _unclaimedAccumulatedProtocolFees = unclaimedAccumulatedProtocolFees[l1Token];\n unclaimedAccumulatedProtocolFees[l1Token] = 0;\n IERC20(l1Token).safeTransfer(protocolFeeCaptureAddress, _unclaimedAccumulatedProtocolFees);\n emit ProtocolFeesCapturedClaimed(l1Token, _unclaimedAccumulatedProtocolFees);\n }\n\n /**\n * @notice Conveniently queries which destination token is mapped to the hash of an l1 token + destination chain ID.\n * @param destinationChainId Where destination token is deployed.\n * @param l1Token Ethereum version token.\n * @return destinationToken address The destination token that is sent to spoke pools after this contract bridges\n * the l1Token to the destination chain.\n */\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n override\n returns (address destinationToken)\n {\n return poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, destinationChainId)];\n }\n\n /**\n * @notice This function allows a caller to load the contract with raw ETH to perform L2 calls. This is needed for\n * Arbitrum calls, but may also be needed for others.\n * @dev This function cannot be included in a multicall transaction call because it is payable. A realistic\n * situation where this might be an issue is if the caller is executing a PoolRebalanceLeaf that needs to relay\n * messages to Arbitrum. Relaying messages to Arbitrum requires that this contract has an ETH balance, so in this\n * case the caller would need to pre-load this contract with ETH before multicall-executing the leaf.\n */\n function loadEthForL2Calls() public payable override {}\n\n /*************************************************\n * INTERNAL FUNCTIONS *\n *************************************************/\n\n // Called when a dispute fails due to parameter changes. This effectively resets the state and cancels the request\n // with no loss of funds, thereby enabling a new bundle to be added.\n function _cancelBundle() internal {\n bondToken.transfer(rootBundleProposal.proposer, bondAmount);\n delete rootBundleProposal;\n emit RootBundleCanceled(msg.sender, getCurrentTime());\n }\n\n function _getOptimisticOracle() internal view returns (SkinnyOptimisticOracleInterface) {\n return\n SkinnyOptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.SkinnyOptimisticOracle));\n }\n\n function _getBondTokenFinalFee() internal view returns (uint256) {\n return\n StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store))\n .computeFinalFee(address(bondToken))\n .rawValue;\n }\n\n // Note this method does a lot and wraps together the sending of tokens and updating the pooled token trackers. This\n // is done as a gas saving so we don't need to iterate over the l1Tokens multiple times.\n function _sendTokensToChainAndUpdatePooledTokenTrackers(\n address adapter,\n address spokePool,\n uint256 chainId,\n address[] memory l1Tokens,\n int256[] memory netSendAmounts,\n uint256[] memory bundleLpFees\n ) internal {\n for (uint32 i = 0; i < l1Tokens.length; i++) {\n address l1Token = l1Tokens[i];\n // Validate the L1 -> L2 token route is stored. If it is not then the output of the bridging action\n // could send tokens to the 0x0 address on the L2.\n address l2Token = poolRebalanceRoutes[_poolRebalanceRouteKey(l1Token, chainId)];\n require(l2Token != address(0), \"Route not whitelisted\");\n\n // If the net send amount for this token is positive then: 1) send tokens from L1->L2 to facilitate the L2\n // relayer refund, 2) Update the liquidity trackers for the associated pooled tokens.\n if (netSendAmounts[i] > 0) {\n // Perform delegatecall to use the adapter's code with this contract's context. Opt for delegatecall's\n // complexity in exchange for lower gas costs.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayTokens(address,address,uint256,address)\",\n l1Token, // l1Token.\n l2Token, // l2Token.\n uint256(netSendAmounts[i]), // amount.\n spokePool // to. This should be the spokePool.\n )\n );\n require(success, \"delegatecall failed\");\n\n // Liquid reserves is decreased by the amount sent. utilizedReserves is increased by the amount sent.\n pooledTokens[l1Token].utilizedReserves += netSendAmounts[i];\n pooledTokens[l1Token].liquidReserves -= uint256(netSendAmounts[i]);\n }\n\n // Allocate LP fees and protocol fees from the bundle to the associated pooled token trackers.\n _allocateLpAndProtocolFees(l1Token, bundleLpFees[i]);\n }\n }\n\n function _exchangeRateCurrent(address l1Token) internal returns (uint256) {\n PooledToken storage pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 lpTokenTotalSupply = IERC20(pooledToken.lpToken).totalSupply();\n if (lpTokenTotalSupply == 0) return 1e18; // initial rate is 1:1 between LP tokens and collateral.\n\n // First, update fee counters and local accounting of finalized transfers from L2 -> L1.\n _updateAccumulatedLpFees(pooledToken); // Accumulate all allocated fees from the last time this method was called.\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // ExchangeRate := (liquidReserves + utilizedReserves - undistributedLpFees) / lpTokenSupply\n // Both utilizedReserves and undistributedLpFees contain assigned LP fees. UndistributedLpFees is gradually\n // decreased over the smear duration using _updateAccumulatedLpFees. This means that the exchange rate will\n // gradually increase over time as undistributedLpFees goes to zero.\n // utilizedReserves can be negative. If this is the case, then liquidReserves is offset by an equal\n // and opposite size. LiquidReserves + utilizedReserves will always be larger than undistributedLpFees so this\n // int will always be positive so there is no risk in underflow in type casting in the return line.\n int256 numerator = int256(pooledToken.liquidReserves) +\n pooledToken.utilizedReserves -\n int256(pooledToken.undistributedLpFees);\n return (uint256(numerator) * 1e18) / lpTokenTotalSupply;\n }\n\n // Update internal fee counters by adding in any accumulated fees from the last time this logic was called.\n function _updateAccumulatedLpFees(PooledToken storage pooledToken) internal {\n uint256 accumulatedFees = _getAccumulatedFees(pooledToken.undistributedLpFees, pooledToken.lastLpFeeUpdate);\n pooledToken.undistributedLpFees -= accumulatedFees;\n pooledToken.lastLpFeeUpdate = uint32(getCurrentTime());\n }\n\n // Calculate the unallocated accumulatedFees from the last time the contract was called.\n function _getAccumulatedFees(uint256 undistributedLpFees, uint256 lastLpFeeUpdate) internal view returns (uint256) {\n // accumulatedFees := min(undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction, undistributedLpFees)\n // The min acts to pay out all fees in the case the equation returns more than the remaining fees.\n uint256 timeFromLastInteraction = getCurrentTime() - lastLpFeeUpdate;\n uint256 maxUndistributedLpFees = (undistributedLpFees * lpFeeRatePerSecond * timeFromLastInteraction) / (1e18);\n return maxUndistributedLpFees < undistributedLpFees ? maxUndistributedLpFees : undistributedLpFees;\n }\n\n function _sync(address l1Token) internal {\n // Check if the l1Token balance of the contract is greater than the liquidReserves. If it is then the bridging\n // action from L2 -> L1 has concluded and the local accounting can be updated.\n // Note: this calculation must take into account the bond when it's acting on the bond token and there's an\n // active request.\n uint256 balance = IERC20(l1Token).balanceOf(address(this));\n uint256 balanceSansBond = l1Token == address(bondToken) && _activeRequest() ? balance - bondAmount : balance;\n if (balanceSansBond > pooledTokens[l1Token].liquidReserves) {\n // Note the numerical operation below can send utilizedReserves to negative. This can occur when tokens are\n // dropped onto the contract, exceeding the liquidReserves.\n pooledTokens[l1Token].utilizedReserves -= int256(balanceSansBond - pooledTokens[l1Token].liquidReserves);\n pooledTokens[l1Token].liquidReserves = balanceSansBond;\n }\n }\n\n function _liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) internal returns (uint256) {\n _sync(l1Token); // Fetch any balance changes due to token bridging finalization and factor them in.\n\n // liquidityUtilizationRatio := (relayedAmount + max(utilizedReserves,0)) / (liquidReserves + max(utilizedReserves,0))\n // UtilizedReserves has a dual meaning: if it's greater than zero then it represents funds pending in the bridge\n // that will flow from L2 to L1. In this case, we can use it normally in the equation. However, if it is\n // negative, then it is already counted in liquidReserves. This occurs if tokens are transferred directly to the\n // contract. In this case, ignore it as it is captured in liquid reserves and has no meaning in the numerator.\n PooledToken memory pooledToken = pooledTokens[l1Token]; // Note this is storage so the state can be modified.\n uint256 flooredUtilizedReserves = pooledToken.utilizedReserves > 0 ? uint256(pooledToken.utilizedReserves) : 0;\n uint256 numerator = relayedAmount + flooredUtilizedReserves;\n uint256 denominator = pooledToken.liquidReserves + flooredUtilizedReserves;\n\n // If the denominator equals zero, return 1e18 (max utilization).\n if (denominator == 0) return 1e18;\n\n // In all other cases, return the utilization ratio.\n return (numerator * 1e18) / denominator;\n }\n\n function _allocateLpAndProtocolFees(address l1Token, uint256 bundleLpFees) internal {\n // Calculate the fraction of bundledLpFees that are allocated to the protocol and to the LPs.\n uint256 protocolFeesCaptured = (bundleLpFees * protocolFeeCapturePct) / 1e18;\n uint256 lpFeesCaptured = bundleLpFees - protocolFeesCaptured;\n\n // Assign any LP fees included into the bundle to the pooled token. These LP fees are tracked in the\n // undistributedLpFees and within the utilizedReserves. undistributedLpFees is gradually decreased\n // over the smear duration to give the LPs their rewards over a period of time. Adding to utilizedReserves\n // acts to track these rewards after the smear duration. See _exchangeRateCurrent for more details.\n if (lpFeesCaptured > 0) {\n pooledTokens[l1Token].undistributedLpFees += lpFeesCaptured;\n pooledTokens[l1Token].utilizedReserves += int256(lpFeesCaptured);\n }\n\n // If there are any protocol fees, allocate them to the unclaimed protocol tracker amount.\n if (protocolFeesCaptured > 0) unclaimedAccumulatedProtocolFees[l1Token] += protocolFeesCaptured;\n }\n\n function _relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) internal {\n (address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);\n\n // Perform delegatecall to use the adapter's code with this contract's context.\n (bool success, ) = adapter.delegatecall(\n abi.encodeWithSignature(\n \"relayMessage(address,bytes)\",\n spokePool, // target. This should be the spokePool on the L2.\n functionData\n )\n );\n require(success, \"delegatecall failed\");\n emit SpokePoolAdminFunctionTriggered(chainId, functionData);\n }\n\n function _poolRebalanceRouteKey(address l1Token, uint256 destinationChainId) internal pure returns (bytes32) {\n return keccak256(abi.encode(l1Token, destinationChainId));\n }\n\n function _getInitializedCrossChainContracts(uint256 chainId)\n internal\n view\n returns (address adapter, address spokePool)\n {\n adapter = crossChainContracts[chainId].adapter;\n spokePool = crossChainContracts[chainId].spokePool;\n require(spokePool != address(0), \"SpokePool not initialized\");\n require(adapter.isContract(), \"Adapter not initialized\");\n }\n\n function _activeRequest() internal view returns (bool) {\n return rootBundleProposal.unclaimedPoolRebalanceLeafCount != 0;\n }\n\n // If functionCallStackOriginatesFromOutsideThisContract is true then this was called by the callback function\n // by dropping ETH onto the contract. In this case, deposit the ETH into WETH. This would happen if ETH was sent\n // over the optimism bridge, for example. If false then this was set as a result of unwinding LP tokens, with the\n // intention of sending ETH to the LP. In this case, do nothing as we intend on sending the ETH to the LP.\n function _depositEthToWeth() internal {\n if (functionCallStackOriginatesFromOutsideThisContract()) weth.deposit{ value: msg.value }();\n }\n\n // Added to enable the HubPool to receive ETH. This will occur both when the HubPool unwraps WETH to send to LPs and\n // when ETH is sent over the canonical Optimism bridge, which sends ETH.\n fallback() external payable {\n _depositEthToWeth();\n }\n\n receive() external payable {\n _depositEthToWeth();\n }\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" @@ -62,19 +62,19 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -83,7 +83,7 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" diff --git a/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json b/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json index a44976bf..f246a5bb 100644 --- a/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json +++ b/deployments/rinkeby/solcInputs/fc82eeb0fff4196cd4e0dfec8a3b3aca.json @@ -2,22 +2,22 @@ "language": "Solidity", "sources": { "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of WETH contract for this network. If an origin token matches this, then the caller can optionally\n // instruct this contract to wrap ETH when depositing.\n WETH9 public immutable weth;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n bytes32 indexed relayHash,\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(uint32 indexed rootBundleId, bytes32 relayerRefundRoot, bytes32 slowRelayRoot);\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n weth = WETH9(_wethAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundRoot().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayRoot().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit ETH if the originToken is WETH and this\n * function will handle wrapping ETH.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a WETH contract and there is a msg.value with the transaction\n // then the user is sending ETH. In this case, the ETH should be deposited to WETH.\n if (originToken == address(weth) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n weth.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n numberOfDeposits += 1;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-191 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n for (uint32 i = 0; i < relayerRefundLeaf.refundAmounts.length; i++) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(crossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(hubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-191 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends WETH.\n function _unwrapWETHTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(weth)).safeTransfer(to, amount);\n } else {\n weth.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is weth then unwrap and send eth.\n if (relayData.destinationToken == address(weth)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants WETH, then we can assume that WETH is already in the contract, otherwise we'll need the\n // the user to send WETH to this contract. Regardless, we'll need to unwrap it before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapWETHTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 relayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayHash,\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive ETH. Used when unwrapping Weth.\n receive() external payable {}\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x256 leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" @@ -32,49 +32,49 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // This array is grouped with the two above, and it represents the amount to send or request back from the\n // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool.\n // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero when the\n // rules indicate that a rebalancing action should occur. When a rebalance does occur, runningBalances should be\n // set to zero for this token and the netSendAmounts should be set to the previous runningBalances + relays -\n // deposits in this bundle. If non-zero then it must be set on the SpokePool's RelayerRefundLeaf amountToReturn\n // as -1 * this value to indicate if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The following arrays are required to be the same length. They are parallel arrays for the given chainId and\n // should be ordered by the l1Tokens field. All whitelisted tokens with nonzero relays on this chain in this\n // bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // requestExpirationTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 requestExpirationTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Trees proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n bytes32 proofElement = proof[i];\n if (computedHash <= proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = _efficientHash(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = _efficientHash(proofElement, computedHash);\n }\n }\n return computedHash;\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes memory message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 chainId_;\n\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {}\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {}\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1Weth Ethereum WETH address.\n */\n constructor(address _destination, WETH9 _l1Weth) {\n destination = _destination;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n * @param isWrappedMatic True if token is WMATIC.\n */\n function send(\n PolygonIERC20 token,\n uint256 amount,\n bool isWrappedMatic\n ) public nonReentrant {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(amount);\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (isWrappedMatic) maticToken.withdraw{ value: amount }(amount);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant {\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n receive() external payable {\n // Note: this should only happen on the mainnet side where ETH is sent to the contract directly by the bridge.\n if (functionCallStackOriginatesFromOutsideThisContract()) l1Weth.deposit{ value: address(this).balance }();\n }\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {}\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, _allowances[owner][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = _allowances[owner][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Spend `amount` form the allowance of `owner` toward `spender`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" @@ -83,10 +83,10 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces _wethAddress for this network since MATIC is the gas token and sent via msg.value\n * on Polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(fxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(polygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WETH is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress),\n relayerRefundLeaf.amountToReturn,\n address(weth) == relayerRefundLeaf.l2TokenAddress\n );\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Optimism_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth = address(Lib_PredeployAddresses.OVM_ETH);\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, timerAddress)\n {}\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayRoot(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(weth)) _depositEthToWeth();\n\n _executeSlowRelayRoot(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundRoot(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) _depositEthToWeth();\n\n _executeRelayerRefundRoot(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) weth.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(weth)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -104,7 +104,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"OVM_XCHAIN: messenger contract unauthenticated\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 5_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -113,34 +113,34 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system helper contract.\n * @param _fxStateSender FxStateSender Polygon system helper contract.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes memory message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(rootChainManager), amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes memory message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes memory message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n // solhint-disable-next-line no-inline-assembly\n\n bool success;\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(l1Token, to, amount, l2GasLimit, l2GasPrice, data);\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -149,25 +149,25 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _append(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _append(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _append(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/common/implementation/AncillaryData.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Library for encoding and decoding ancillary data for DVM price requests.\n * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via\n * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value\n * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity\n * smart contracts. More details on UMA's ancillary data guidelines below:\n * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit\n */\nlibrary AncillaryData {\n // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.\n // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.\n function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {\n unchecked {\n uint256 x = uint256(bytesIn);\n\n // Nibble interleave\n x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;\n x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;\n x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;\n x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;\n x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;\n x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n\n // Hex encode\n uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;\n uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;\n uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;\n x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;\n\n // Return the result.\n return bytes32(x);\n }\n }\n\n /**\n * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.\n * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.\n * This has minor changes from the toUtf8BytesAddress to control for the size of the input.\n * @param bytesIn bytes32 to encode.\n * @return utf8 encoded bytes32.\n */\n function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {\n return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));\n }\n\n /**\n * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.\n * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447\n * @dev Will return address in all lower case characters and without the leading 0x.\n * @param x address to encode.\n * @return utf8 encoded address bytes.\n */\n function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {\n return\n abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));\n }\n\n /**\n * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.\n * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.\n */\n function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {\n if (x == 0) {\n return \"0\";\n }\n uint256 j = x;\n uint256 len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint256 k = len;\n while (x != 0) {\n k = k - 1;\n uint8 temp = (48 + uint8(x - (x / 10) * 10));\n bytes1 b1 = bytes1(temp);\n bstr[k] = b1;\n x /= 10;\n }\n return bstr;\n }\n\n function appendKeyValueBytes32(\n bytes memory currentAncillaryData,\n bytes memory key,\n bytes32 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is an address that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueAddress(\n bytes memory currentAncillaryData,\n bytes memory key,\n address value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));\n }\n\n /**\n * @notice Adds \"key:value\" to `currentAncillaryData` where `value` is a uint that first needs to be converted\n * to utf8 bytes. For example, if `utf8(currentAncillaryData)=\"k1:v1\"`, then this function will return\n * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.\n * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.\n * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.\n * @return Newly appended ancillary data.\n */\n function appendKeyValueUint(\n bytes memory currentAncillaryData,\n bytes memory key,\n uint256 value\n ) internal pure returns (bytes memory) {\n bytes memory prefix = constructPrefix(currentAncillaryData, key);\n return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));\n }\n\n /**\n * @notice Helper method that returns the left hand side of a \"key:value\" pair plus the colon \":\" and a leading\n * comma \",\" if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to\n * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.\n */\n function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {\n if (currentAncillaryData.length > 0) {\n return abi.encodePacked(\",\", key, \":\");\n } else {\n return abi.encodePacked(key, \":\");\n }\n }\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": { diff --git a/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json b/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json index 86f3f81e..ce0d44f4 100644 --- a/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json +++ b/deployments/zksync-goerli/solcInputs/ee6ad487568ec11f1abbf35d827b46d3.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "contracts/AcrossConfigStore.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title Allows admin to set and update configuration settings for full contract system. These settings are designed\n * to be consumed by off-chain bots, rather than by other contracts.\n * @dev This contract should not perform any validation on the setting values and should be owned by the governance\n * system of the full contract suite..\n */\ncontract AcrossConfigStore is Ownable, MultiCaller {\n // General dictionary where admin can associate variables with specific L1 tokens, like the Rate Model and Token\n // Transfer Thresholds.\n mapping(address => string) public l1TokenConfig;\n\n // General dictionary where admin can store global variables like `MAX_POOL_REBALANCE_LEAF_SIZE` and\n // `MAX_RELAYER_REPAYMENT_LEAF_SIZE` that off-chain agents can query.\n mapping(bytes32 => string) public globalConfig;\n\n event UpdatedTokenConfig(address indexed key, string value);\n event UpdatedGlobalConfig(bytes32 indexed key, string value);\n\n /**\n * @notice Updates token config.\n * @param l1Token the l1 token address to update value for.\n * @param value Value to update.\n */\n function updateTokenConfig(address l1Token, string memory value) external onlyOwner {\n l1TokenConfig[l1Token] = value;\n emit UpdatedTokenConfig(l1Token, value);\n }\n\n /**\n * @notice Updates global config.\n * @param key Key to update.\n * @param value Value to update.\n */\n function updateGlobalConfig(bytes32 key, string calldata value) external onlyOwner {\n globalConfig[key] = value;\n emit UpdatedGlobalConfig(key, value);\n }\n}\n" }, "@uma/core/contracts/common/implementation/MultiCaller.sol": { "content": "// This contract is taken from Uniswaps's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)\n// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value\n// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.\npragma solidity ^0.8.0;\n\n/// @title MultiCaller\n/// @notice Enables calling multiple methods in a single call to the contract\ncontract MultiCaller {\n function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {\n require(msg.value == 0, \"Only multicall with 0 value\");\n results = new bytes[](data.length);\n for (uint256 i = 0; i < data.length; i++) {\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n\n if (!success) {\n // Next 5 lines from https://ethereum.stackexchange.com/a/83577\n if (result.length < 68) revert();\n assembly {\n result := add(result, 0x04)\n }\n revert(abi.decode(result, (string)));\n }\n\n results[i] = result;\n }\n }\n}\n" @@ -26,76 +26,76 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" }, "contracts/PolygonTokenBridger.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Lockable.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Polygon Registry contract that stores their addresses.\ninterface PolygonRegistry {\n function erc20Predicate() external returns (address);\n}\n\n// Polygon ERC20Predicate contract that handles Plasma exits (only used for Matic).\ninterface PolygonERC20Predicate {\n function startExitWithBurntTokens(bytes calldata data) external;\n}\n\n// ERC20s (on polygon) compatible with polygon's bridge have a withdraw method.\ninterface PolygonIERC20 is IERC20 {\n function withdraw(uint256 amount) external;\n}\n\ninterface MaticToken {\n function withdraw(uint256 amount) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum and Polygon to facilitate token transfers from Polygon to the HubPool and back.\n * @dev Because Polygon only allows withdrawals from a particular address to go to that same address on mainnet, we need to\n * have some sort of contract that can guarantee identical addresses on Polygon and Ethereum. This contract is intended\n * to be completely immutable, so it's guaranteed that the contract on each side is configured identically as long as\n * it is created via create2. create2 is an alternative creation method that uses a different address determination\n * mechanism from normal create.\n * Normal create: address = hash(deployer_address, deployer_nonce)\n * create2: address = hash(0xFF, sender, salt, bytecode)\n * This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the\n * sender.\n */\ncontract PolygonTokenBridger is Lockable {\n using SafeERC20 for PolygonIERC20;\n using SafeERC20 for IERC20;\n\n // Gas token for Polygon.\n MaticToken public constant maticToken = MaticToken(0x0000000000000000000000000000000000001010);\n\n // Should be set to HubPool on Ethereum, or unused on Polygon.\n address public immutable destination;\n\n // Registry that stores L1 polygon addresses.\n PolygonRegistry public immutable l1PolygonRegistry;\n\n // WETH contract on Ethereum.\n WETH9 public immutable l1Weth;\n\n // Wrapped Matic on Polygon\n address public immutable l2WrappedMatic;\n\n // Chain id for the L1 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the mainnet chainId 1.\n uint256 public immutable l1ChainId;\n\n // Chain id for the L2 that this contract is deployed on or communicates with.\n // For example: if this contract were meant to facilitate transfers from polygon to mainnet, this value would be\n // the polygon chainId 137.\n uint256 public immutable l2ChainId;\n\n modifier onlyChainId(uint256 chainId) {\n _requireChainId(chainId);\n _;\n }\n\n /**\n * @notice Constructs Token Bridger contract.\n * @param _destination Where to send tokens to for this network.\n * @param _l1PolygonRegistry L1 registry that stores updated addresses of polygon contracts. This should always be\n * set to the L1 registry regardless if whether it's deployed on L2 or L1.\n * @param _l1Weth L1 WETH address.\n * @param _l2WrappedMatic L2 address of wrapped matic token.\n * @param _l1ChainId the chain id for the L1 in this environment.\n * @param _l2ChainId the chain id for the L2 in this environment.\n */\n constructor(\n address _destination,\n PolygonRegistry _l1PolygonRegistry,\n WETH9 _l1Weth,\n address _l2WrappedMatic,\n uint256 _l1ChainId,\n uint256 _l2ChainId\n ) {\n destination = _destination;\n l1PolygonRegistry = _l1PolygonRegistry;\n l1Weth = _l1Weth;\n l2WrappedMatic = _l2WrappedMatic;\n l1ChainId = _l1ChainId;\n l2ChainId = _l2ChainId;\n }\n\n /**\n * @notice Called by Polygon SpokePool to send tokens over bridge to contract with the same address as this.\n * @notice The caller of this function must approve this contract to spend amount of token.\n * @param token Token to bridge.\n * @param amount Amount to bridge.\n */\n function send(PolygonIERC20 token, uint256 amount) public nonReentrant onlyChainId(l2ChainId) {\n token.safeTransferFrom(msg.sender, address(this), amount);\n\n // In the wMatic case, this unwraps. For other ERC20s, this is the burn/send action.\n token.withdraw(token.balanceOf(address(this)));\n\n // This takes the token that was withdrawn and calls withdraw on the \"native\" ERC20.\n if (address(token) == l2WrappedMatic)\n maticToken.withdraw{ value: address(this).balance }(address(this).balance);\n }\n\n /**\n * @notice Called by someone to send tokens to the destination, which should be set to the HubPool.\n * @param token Token to send to destination.\n */\n function retrieve(IERC20 token) public nonReentrant onlyChainId(l1ChainId) {\n if (address(token) == address(l1Weth)) {\n // For WETH, there is a pre-deposit step to ensure any ETH that has been sent to the contract is captured.\n l1Weth.deposit{ value: address(this).balance }();\n }\n token.safeTransfer(destination, token.balanceOf(address(this)));\n }\n\n /**\n * @notice Called to initiate an l1 exit (withdrawal) of matic tokens that have been sent over the plasma bridge.\n * @param data the proof data to trigger the exit. Can be generated using the maticjs-plasma package.\n */\n function callExit(bytes memory data) public nonReentrant onlyChainId(l1ChainId) {\n PolygonERC20Predicate erc20Predicate = PolygonERC20Predicate(l1PolygonRegistry.erc20Predicate());\n erc20Predicate.startExitWithBurntTokens(data);\n }\n\n receive() external payable {\n // This method is empty to avoid any gas expendatures that might cause transfers to fail.\n // Note: the fact that there is _no_ code in this function means that matic can be erroneously transferred in\n // to the contract on the polygon side. These tokens would be locked indefinitely since the receive function\n // cannot be called on the polygon side. While this does have some downsides, the lack of any functionality\n // in this function means that it has no chance of running out of gas on transfers, which is a much more\n // important benefit. This just makes the matic token risk similar to that of ERC20s that are erroneously\n // sent to the contract.\n }\n\n function _requireChainId(uint256 chainId) internal view {\n require(block.chainid == chainId, \"Cannot run method on this chain\");\n }\n}\n" }, "contracts/Lockable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract\n * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol\n * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.\n * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition\n * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported\n * by uma/contracts.\n */\ncontract Lockable {\n bool internal _notEntered;\n\n constructor() {\n // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every\n // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full\n // refund coming into effect.\n _notEntered = true;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a nonReentrant function from another nonReentrant function is not supported. It is possible to\n * prevent this from happening by making the nonReentrant function external, and making it call a private\n * function that does the actual state modification.\n */\n modifier nonReentrant() {\n _preEntranceCheck();\n _preEntranceSet();\n _;\n _postEntranceReset();\n }\n\n /**\n * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.\n */\n modifier nonReentrantView() {\n _preEntranceCheck();\n _;\n }\n\n /**\n * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call\n * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH\n * being dropped onto the contract externally or due to ETH dropped on the the contract from within a method in this\n * contract, such as unwrapping WETH to ETH within the contract.\n */\n function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {\n return _notEntered;\n }\n\n // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.\n // On entry into a function, _preEntranceCheck() should always be called to check if the function is being\n // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and\n // then call _postEntranceReset().\n // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.\n function _preEntranceCheck() internal view {\n // On the first call to nonReentrant, _notEntered will be true\n require(_notEntered, \"ReentrancyGuard: reentrant call\");\n }\n\n function _preEntranceSet() internal {\n // Any calls to nonReentrant after this point will fail\n _notEntered = false;\n }\n\n function _postEntranceReset() internal {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _notEntered = true;\n }\n}\n" }, "contracts/interfaces/WETH9.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface WETH9 {\n function withdraw(uint256 wad) external;\n\n function deposit() external payable;\n\n function balanceOf(address guy) external view returns (uint256 wad);\n\n function transfer(address guy, uint256 wad) external;\n}\n" }, "contracts/test/PolygonERC20Test.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\nimport \"../PolygonTokenBridger.sol\";\n\n/**\n * @notice Simulated Polygon ERC20 for use in testing PolygonTokenBridger.\n */\ncontract PolygonERC20Test is ExpandedERC20, PolygonIERC20 {\n constructor() ExpandedERC20(\"Polygon Test\", \"POLY_TEST\", 18) {} // solhint-disable-line no-empty-blocks\n\n function withdraw(uint256 amount) public {\n _burn(msg.sender, amount);\n }\n}\n" }, "@uma/core/contracts/common/implementation/ExpandedERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./MultiRole.sol\";\nimport \"../interfaces/ExpandedIERC20.sol\";\n\n/**\n * @title An ERC20 with permissioned burning and minting. The contract deployer will initially\n * be the owner who is capable of adding new roles.\n */\ncontract ExpandedERC20 is ExpandedIERC20, ERC20, MultiRole {\n enum Roles {\n // Can set the minter and burner.\n Owner,\n // Addresses that can mint new tokens.\n Minter,\n // Addresses that can burn tokens that address owns.\n Burner\n }\n\n uint8 _decimals;\n\n /**\n * @notice Constructs the ExpandedERC20.\n * @param _tokenName The name which describes the new token.\n * @param _tokenSymbol The ticker abbreviation of the name. Ideally < 5 chars.\n * @param _tokenDecimals The number of decimals to define token precision.\n */\n constructor(\n string memory _tokenName,\n string memory _tokenSymbol,\n uint8 _tokenDecimals\n ) ERC20(_tokenName, _tokenSymbol) {\n _decimals = _tokenDecimals;\n _createExclusiveRole(uint256(Roles.Owner), uint256(Roles.Owner), msg.sender);\n _createSharedRole(uint256(Roles.Minter), uint256(Roles.Owner), new address[](0));\n _createSharedRole(uint256(Roles.Burner), uint256(Roles.Owner), new address[](0));\n }\n\n function decimals() public view virtual override(ERC20) returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev Mints `value` tokens to `recipient`, returning true on success.\n * @param recipient address to mint to.\n * @param value amount of tokens to mint.\n * @return True if the mint succeeded, or False.\n */\n function mint(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Minter))\n returns (bool)\n {\n _mint(recipient, value);\n return true;\n }\n\n /**\n * @dev Burns `value` tokens owned by `msg.sender`.\n * @param value amount of tokens to burn.\n */\n function burn(uint256 value) external override onlyRoleHolder(uint256(Roles.Burner)) {\n _burn(msg.sender, value);\n }\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n * @return True if the burn succeeded, or False.\n */\n function burnFrom(address recipient, uint256 value)\n external\n override\n onlyRoleHolder(uint256(Roles.Burner))\n returns (bool)\n {\n _burn(recipient, value);\n return true;\n }\n\n /**\n * @notice Add Minter role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Minter role is added.\n */\n function addMinter(address account) external virtual override {\n addMember(uint256(Roles.Minter), account);\n }\n\n /**\n * @notice Add Burner role to account.\n * @dev The caller must have the Owner role.\n * @param account The address to which the Burner role is added.\n */\n function addBurner(address account) external virtual override {\n addMember(uint256(Roles.Burner), account);\n }\n\n /**\n * @notice Reset Owner role to account.\n * @dev The caller must have the Owner role.\n * @param account The new holder of the Owner role.\n */\n function resetOwner(address account) external virtual override {\n resetMember(uint256(Roles.Owner), account);\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" }, "@uma/core/contracts/common/implementation/MultiRole.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nlibrary Exclusive {\n struct RoleMembership {\n address member;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.member == memberToCheck;\n }\n\n function resetMember(RoleMembership storage roleMembership, address newMember) internal {\n require(newMember != address(0x0), \"Cannot set an exclusive role to 0x0\");\n roleMembership.member = newMember;\n }\n\n function getMember(RoleMembership storage roleMembership) internal view returns (address) {\n return roleMembership.member;\n }\n\n function init(RoleMembership storage roleMembership, address initialMember) internal {\n resetMember(roleMembership, initialMember);\n }\n}\n\nlibrary Shared {\n struct RoleMembership {\n mapping(address => bool) members;\n }\n\n function isMember(RoleMembership storage roleMembership, address memberToCheck) internal view returns (bool) {\n return roleMembership.members[memberToCheck];\n }\n\n function addMember(RoleMembership storage roleMembership, address memberToAdd) internal {\n require(memberToAdd != address(0x0), \"Cannot add 0x0 to a shared role\");\n roleMembership.members[memberToAdd] = true;\n }\n\n function removeMember(RoleMembership storage roleMembership, address memberToRemove) internal {\n roleMembership.members[memberToRemove] = false;\n }\n\n function init(RoleMembership storage roleMembership, address[] memory initialMembers) internal {\n for (uint256 i = 0; i < initialMembers.length; i++) {\n addMember(roleMembership, initialMembers[i]);\n }\n }\n}\n\n/**\n * @title Base class to manage permissions for the derived class.\n */\nabstract contract MultiRole {\n using Exclusive for Exclusive.RoleMembership;\n using Shared for Shared.RoleMembership;\n\n enum RoleType { Invalid, Exclusive, Shared }\n\n struct Role {\n uint256 managingRole;\n RoleType roleType;\n Exclusive.RoleMembership exclusiveRoleMembership;\n Shared.RoleMembership sharedRoleMembership;\n }\n\n mapping(uint256 => Role) private roles;\n\n event ResetExclusiveMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event AddedSharedMember(uint256 indexed roleId, address indexed newMember, address indexed manager);\n event RemovedSharedMember(uint256 indexed roleId, address indexed oldMember, address indexed manager);\n\n /**\n * @notice Reverts unless the caller is a member of the specified roleId.\n */\n modifier onlyRoleHolder(uint256 roleId) {\n require(holdsRole(roleId, msg.sender), \"Sender does not hold required role\");\n _;\n }\n\n /**\n * @notice Reverts unless the caller is a member of the manager role for the specified roleId.\n */\n modifier onlyRoleManager(uint256 roleId) {\n require(holdsRole(roles[roleId].managingRole, msg.sender), \"Can only be called by a role manager\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, exclusive roleId.\n */\n modifier onlyExclusive(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Exclusive, \"Must be called on an initialized Exclusive role\");\n _;\n }\n\n /**\n * @notice Reverts unless the roleId represents an initialized, shared roleId.\n */\n modifier onlyShared(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Shared, \"Must be called on an initialized Shared role\");\n _;\n }\n\n /**\n * @notice Whether `memberToCheck` is a member of roleId.\n * @dev Reverts if roleId does not correspond to an initialized role.\n * @param roleId the Role to check.\n * @param memberToCheck the address to check.\n * @return True if `memberToCheck` is a member of `roleId`.\n */\n function holdsRole(uint256 roleId, address memberToCheck) public view returns (bool) {\n Role storage role = roles[roleId];\n if (role.roleType == RoleType.Exclusive) {\n return role.exclusiveRoleMembership.isMember(memberToCheck);\n } else if (role.roleType == RoleType.Shared) {\n return role.sharedRoleMembership.isMember(memberToCheck);\n }\n revert(\"Invalid roleId\");\n }\n\n /**\n * @notice Changes the exclusive role holder of `roleId` to `newMember`.\n * @dev Reverts if the caller is not a member of the managing role for `roleId` or if `roleId` is not an\n * initialized, ExclusiveRole.\n * @param roleId the ExclusiveRole membership to modify.\n * @param newMember the new ExclusiveRole member.\n */\n function resetMember(uint256 roleId, address newMember) public onlyExclusive(roleId) onlyRoleManager(roleId) {\n roles[roleId].exclusiveRoleMembership.resetMember(newMember);\n emit ResetExclusiveMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Gets the current holder of the exclusive role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, exclusive role.\n * @param roleId the ExclusiveRole membership to check.\n * @return the address of the current ExclusiveRole member.\n */\n function getMember(uint256 roleId) public view onlyExclusive(roleId) returns (address) {\n return roles[roleId].exclusiveRoleMembership.getMember();\n }\n\n /**\n * @notice Adds `newMember` to the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param newMember the new SharedRole member.\n */\n function addMember(uint256 roleId, address newMember) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.addMember(newMember);\n emit AddedSharedMember(roleId, newMember, msg.sender);\n }\n\n /**\n * @notice Removes `memberToRemove` from the shared role, `roleId`.\n * @dev Reverts if `roleId` does not represent an initialized, SharedRole or if the caller is not a member of the\n * managing role for `roleId`.\n * @param roleId the SharedRole membership to modify.\n * @param memberToRemove the current SharedRole member to remove.\n */\n function removeMember(uint256 roleId, address memberToRemove) public onlyShared(roleId) onlyRoleManager(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(memberToRemove);\n emit RemovedSharedMember(roleId, memberToRemove, msg.sender);\n }\n\n /**\n * @notice Removes caller from the role, `roleId`.\n * @dev Reverts if the caller is not a member of the role for `roleId` or if `roleId` is not an\n * initialized, SharedRole.\n * @param roleId the SharedRole membership to modify.\n */\n function renounceMembership(uint256 roleId) public onlyShared(roleId) onlyRoleHolder(roleId) {\n roles[roleId].sharedRoleMembership.removeMember(msg.sender);\n emit RemovedSharedMember(roleId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Reverts if `roleId` is not initialized.\n */\n modifier onlyValidRole(uint256 roleId) {\n require(roles[roleId].roleType != RoleType.Invalid, \"Attempted to use an invalid roleId\");\n _;\n }\n\n /**\n * @notice Reverts if `roleId` is initialized.\n */\n modifier onlyInvalidRole(uint256 roleId) {\n require(roles[roleId].roleType == RoleType.Invalid, \"Cannot use a pre-existing role\");\n _;\n }\n\n /**\n * @notice Internal method to initialize a shared role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMembers` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createSharedRole(\n uint256 roleId,\n uint256 managingRoleId,\n address[] memory initialMembers\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Shared;\n role.managingRole = managingRoleId;\n role.sharedRoleMembership.init(initialMembers);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage a shared role\"\n );\n }\n\n /**\n * @notice Internal method to initialize an exclusive role, `roleId`, which will be managed by `managingRoleId`.\n * `initialMember` will be immediately added to the role.\n * @dev Should be called by derived contracts, usually at construction time. Will revert if the role is already\n * initialized.\n */\n function _createExclusiveRole(\n uint256 roleId,\n uint256 managingRoleId,\n address initialMember\n ) internal onlyInvalidRole(roleId) {\n Role storage role = roles[roleId];\n role.roleType = RoleType.Exclusive;\n role.managingRole = managingRoleId;\n role.exclusiveRoleMembership.init(initialMember);\n require(\n roles[managingRoleId].roleType != RoleType.Invalid,\n \"Attempted to use an invalid role to manage an exclusive role\"\n );\n }\n}\n" }, "@uma/core/contracts/common/interfaces/ExpandedIERC20.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title ERC20 interface that includes burn and mint methods.\n */\nabstract contract ExpandedIERC20 is IERC20 {\n /**\n * @notice Burns a specific amount of the caller's tokens.\n * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.\n */\n function burn(uint256 value) external virtual;\n\n /**\n * @dev Burns `value` tokens owned by `recipient`.\n * @param recipient address to burn tokens from.\n * @param value amount of tokens to burn.\n */\n function burnFrom(address recipient, uint256 value) external virtual returns (bool);\n\n /**\n * @notice Mints tokens and adds them to the balance of the `to` address.\n * @dev This method should be permissioned to only allow designated parties to mint tokens.\n */\n function mint(address to, uint256 value) external virtual returns (bool);\n\n function addMinter(address account) external virtual;\n\n function addBurner(address account) external virtual;\n\n function resetOwner(address account) external virtual;\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" }, "contracts/Polygon_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./PolygonTokenBridger.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// IFxMessageProcessor represents interface to process messages.\ninterface IFxMessageProcessor {\n function processMessageFromRoot(\n uint256 stateId,\n address rootMessageSender,\n bytes calldata data\n ) external;\n}\n\n/**\n * @notice Polygon specific SpokePool.\n */\ncontract Polygon_SpokePool is IFxMessageProcessor, SpokePool {\n using SafeERC20 for PolygonIERC20;\n\n // Address of FxChild which sends and receives messages to and from L1.\n address public fxChild;\n\n // Contract deployed on L1 and L2 processes all cross-chain transfers between this contract and the the HubPool.\n // Required because bridging tokens from Polygon to Ethereum has special constraints.\n PolygonTokenBridger public polygonTokenBridger;\n\n // Internal variable that only flips temporarily to true upon receiving messages from L1. Used to authenticate that\n // the caller is the fxChild AND that the fxChild called processMessageFromRoot\n bool private callValidated = false;\n\n event PolygonTokensBridged(address indexed token, address indexed receiver, uint256 amount);\n event SetFxChild(address indexed newFxChild);\n event SetPolygonTokenBridger(address indexed polygonTokenBridger);\n\n // Note: validating calls this way ensures that strange calls coming from the fxChild won't be misinterpreted.\n // Put differently, just checking that msg.sender == fxChild is not sufficient.\n // All calls that have admin privileges must be fired from within the processMessageFromRoot method that's gone\n // through validation where the sender is checked and the root (mainnet) sender is also validated.\n // This modifier sets the callValidated variable so this condition can be checked in _requireAdminSender().\n modifier validateInternalCalls() {\n // Make sure callValidated is set to True only once at beginning of processMessageFromRoot, which prevents\n // processMessageFromRoot from being re-entered.\n require(!callValidated, \"callValidated already set\");\n\n // This sets a variable indicating that we're now inside a validated call.\n // Note: this is used by other methods to ensure that this call has been validated by this method and is not\n // spoofed. See\n callValidated = true;\n\n _;\n\n // Reset callValidated to false to disallow admin calls after this method exits.\n callValidated = false;\n }\n\n /**\n * @notice Construct the Polygon SpokePool.\n * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wmaticAddress Replaces wrappedNativeToken for this network since MATIC is the native currency on polygon.\n * @param _fxChild FxChild contract, changeable by Admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n PolygonTokenBridger _polygonTokenBridger,\n address _crossDomainAdmin,\n address _hubPool,\n address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon.\n address _fxChild,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) {\n polygonTokenBridger = _polygonTokenBridger;\n fxChild = _fxChild;\n }\n\n /********************************************************\n * POLYGON-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change FxChild address. Callable only by admin via processMessageFromRoot.\n * @param newFxChild New FxChild.\n */\n function setFxChild(address newFxChild) public onlyAdmin nonReentrant {\n fxChild = newFxChild;\n emit SetFxChild(newFxChild);\n }\n\n /**\n * @notice Change polygonTokenBridger address. Callable only by admin via processMessageFromRoot.\n * @param newPolygonTokenBridger New Polygon Token Bridger contract.\n */\n function setPolygonTokenBridger(address payable newPolygonTokenBridger) public onlyAdmin nonReentrant {\n polygonTokenBridger = PolygonTokenBridger(newPolygonTokenBridger);\n emit SetPolygonTokenBridger(address(newPolygonTokenBridger));\n }\n\n /**\n * @notice Called by FxChild upon receiving L1 message that targets this contract. Performs an additional check\n * that the L1 caller was the expected cross domain admin, and then delegate calls.\n * @notice Polygon bridge only executes this external function on the target Polygon contract when relaying\n * messages from L1, so all functions on this SpokePool are expected to originate via this call.\n * @dev stateId value isn't used because it isn't relevant for this method. It doesn't care what state sync\n * triggered this call.\n * @param rootMessageSender Original L1 sender of data.\n * @param data ABI encoded function call to execute on this contract.\n */\n function processMessageFromRoot(\n uint256, /*stateId*/\n address rootMessageSender,\n bytes calldata data\n ) public validateInternalCalls {\n // Validation logic.\n require(msg.sender == fxChild, \"Not from fxChild\");\n require(rootMessageSender == crossDomainAdmin, \"Not from mainnet admin\");\n\n // This uses delegatecall to take the information in the message and process it as a function call on this contract.\n (bool success, ) = address(this).delegatecall(data);\n require(success, \"delegatecall failed\");\n }\n\n /**\n * @notice Allows the caller to trigger the wrapping of any unwrapped matic tokens.\n * @dev Matic sends via L1 -> L2 bridging actions don't call into the contract receiving the tokens, so wrapping\n * must be done via a separate transaction.\n */\n function wrap() public nonReentrant {\n _wrap();\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @dev this is only overridden to wrap any matic the contract holds before running.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override nonReentrant {\n _wrap();\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain. This is only overridden to call\n * wrap before running the function.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _wrap();\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n PolygonIERC20(relayerRefundLeaf.l2TokenAddress).safeIncreaseAllowance(\n address(polygonTokenBridger),\n relayerRefundLeaf.amountToReturn\n );\n\n // Note: WrappedNativeToken is WMATIC on matic, so this tells the tokenbridger that this is an unwrappable native token.\n polygonTokenBridger.send(PolygonIERC20(relayerRefundLeaf.l2TokenAddress), relayerRefundLeaf.amountToReturn);\n\n emit PolygonTokensBridged(relayerRefundLeaf.l2TokenAddress, address(this), relayerRefundLeaf.amountToReturn);\n }\n\n function _wrap() internal {\n uint256 balance = address(this).balance;\n if (balance > 0) wrappedNativeToken.deposit{ value: balance }();\n }\n\n // @dev: This contract will trigger admin functions internally via the `processMessageFromRoot`, which is why\n // the `callValidated` check is made below and why we use the `validateInternalCalls` modifier on\n // `processMessageFromRoot`. This prevents calling the admin functions from any other method besides\n // `processMessageFromRoot`.\n function _requireAdminSender() internal view override {\n require(callValidated, \"Must call processMessageFromRoot\");\n }\n}\n" }, "contracts/SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./MerkleLib.sol\";\nimport \"./interfaces/WETH9.sol\";\nimport \"./Lockable.sol\";\nimport \"./SpokePoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@uma/core/contracts/common/implementation/Testable.sol\";\nimport \"@uma/core/contracts/common/implementation/MultiCaller.sol\";\n\n/**\n * @title SpokePool\n * @notice Base contract deployed on source and destination chains enabling depositors to transfer assets from source to\n * destination. Deposit orders are fulfilled by off-chain relayers who also interact with this contract. Deposited\n * tokens are locked on the source chain and relayers send the recipient the desired token currency and amount\n * on the destination chain. Locked source chain tokens are later sent over the canonical token bridge to L1 HubPool.\n * Relayers are refunded with destination tokens out of this contract after another off-chain actor, a \"data worker\",\n * submits a proof that the relayer correctly submitted a relay on this SpokePool.\n */\nabstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCaller {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // Address of the L1 contract that acts as the owner of this SpokePool. If this contract is deployed on Ethereum,\n // then this address should be set to the same owner as the HubPool and the whole system.\n address public crossDomainAdmin;\n\n // Address of the L1 contract that will send tokens to and receive tokens from this contract to fund relayer\n // refunds and slow relays.\n address public hubPool;\n\n // Address of wrappedNativeToken contract for this network. If an origin token matches this, then the caller can\n // optionally instruct this contract to wrap native tokens when depositing (ie ETH->WETH or MATIC->WMATIC).\n WETH9 public immutable wrappedNativeToken;\n\n // Any deposit quote times greater than or less than this value to the current contract time is blocked. Forces\n // caller to use an approximately \"current\" realized fee. Defaults to 10 minutes.\n uint32 public depositQuoteTimeBuffer = 600;\n\n // Count of deposits is used to construct a unique deposit identifier for this spoke pool.\n uint32 public numberOfDeposits;\n\n // This contract can store as many root bundles as the HubPool chooses to publish here.\n RootBundle[] public rootBundles;\n\n // Origin token to destination token routings can be turned on or off, which can enable or disable deposits.\n mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;\n\n // Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay\n // attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to\n // relay, the fees, and the agents are all parameters included in the hash key.\n mapping(bytes32 => uint256) public relayFills;\n\n /****************************************\n * EVENTS *\n ****************************************/\n event SetXDomainAdmin(address indexed newAdmin);\n event SetHubPool(address indexed newHubPool);\n event EnabledDepositRoute(address indexed originToken, uint256 indexed destinationChainId, bool enabled);\n event SetDepositQuoteTimeBuffer(uint32 newBuffer);\n event FundsDeposited(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n address indexed originToken,\n address recipient,\n address indexed depositor\n );\n event RequestedSpeedUpDeposit(\n uint64 newRelayerFeePct,\n uint32 indexed depositId,\n address indexed depositor,\n bytes depositorSignature\n );\n event FilledRelay(\n uint256 amount,\n uint256 totalFilledAmount,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint64 appliedRelayerFeePct,\n uint64 realizedLpFeePct,\n uint32 depositId,\n address destinationToken,\n address indexed relayer,\n address indexed depositor,\n address recipient,\n bool isSlowRelay\n );\n event RelayedRootBundle(\n uint32 indexed rootBundleId,\n bytes32 indexed relayerRefundRoot,\n bytes32 indexed slowRelayRoot\n );\n event ExecutedRelayerRefundRoot(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint256[] refundAmounts,\n uint32 indexed rootBundleId,\n uint32 indexed leafId,\n address l2TokenAddress,\n address[] refundAddresses,\n address caller\n );\n event TokensBridged(\n uint256 amountToReturn,\n uint256 indexed chainId,\n uint32 indexed leafId,\n address indexed l2TokenAddress,\n address caller\n );\n event EmergencyDeleteRootBundle(uint256 indexed rootBundleId);\n\n /**\n * @notice Construct the base SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wrappedNativeTokenAddress,\n address timerAddress\n ) Testable(timerAddress) {\n _setCrossDomainAdmin(_crossDomainAdmin);\n _setHubPool(_hubPool);\n wrappedNativeToken = WETH9(_wrappedNativeTokenAddress);\n }\n\n /****************************************\n * MODIFIERS *\n ****************************************/\n\n // Implementing contract needs to override _requireAdminSender() to ensure that admin functions are protected\n // appropriately.\n modifier onlyAdmin() {\n _requireAdminSender();\n _;\n }\n\n /**************************************\n * ADMIN FUNCTIONS *\n **************************************/\n\n /**\n * @notice Change cross domain admin address. Callable by admin only.\n * @param newCrossDomainAdmin New cross domain admin.\n */\n function setCrossDomainAdmin(address newCrossDomainAdmin) public override onlyAdmin nonReentrant {\n _setCrossDomainAdmin(newCrossDomainAdmin);\n }\n\n /**\n * @notice Change L1 hub pool address. Callable by admin only.\n * @param newHubPool New hub pool.\n */\n function setHubPool(address newHubPool) public override onlyAdmin nonReentrant {\n _setHubPool(newHubPool);\n }\n\n /**\n * @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.\n * @param originToken Token that depositor can deposit to this contract.\n * @param destinationChainId Chain ID for where depositor wants to receive funds.\n * @param enabled True to enable deposits, False otherwise.\n */\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enabled\n ) public override onlyAdmin nonReentrant {\n enabledDepositRoutes[originToken][destinationChainId] = enabled;\n emit EnabledDepositRoute(originToken, destinationChainId, enabled);\n }\n\n /**\n * @notice Change allowance for deposit quote time to differ from current block time. Callable by admin only.\n * @param newDepositQuoteTimeBuffer New quote time buffer.\n */\n function setDepositQuoteTimeBuffer(uint32 newDepositQuoteTimeBuffer) public override onlyAdmin nonReentrant {\n depositQuoteTimeBuffer = newDepositQuoteTimeBuffer;\n emit SetDepositQuoteTimeBuffer(newDepositQuoteTimeBuffer);\n }\n\n /**\n * @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill\n * slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is\n * designed to be called as part of a cross-chain message from the HubPool's executeRootBundle method.\n * @param relayerRefundRoot Merkle root containing relayer refund leaves that can be individually executed via\n * executeRelayerRefundLeaf().\n * @param slowRelayRoot Merkle root containing slow relay fulfillment leaves that can be individually executed via\n * executeSlowRelayLeaf().\n */\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) public override onlyAdmin nonReentrant {\n uint32 rootBundleId = uint32(rootBundles.length);\n RootBundle storage rootBundle = rootBundles.push();\n rootBundle.relayerRefundRoot = relayerRefundRoot;\n rootBundle.slowRelayRoot = slowRelayRoot;\n emit RelayedRootBundle(rootBundleId, relayerRefundRoot, slowRelayRoot);\n }\n\n /**\n * @notice This method is intended to only be used in emergencies where a bad root bundle has reached the\n * SpokePool.\n * @param rootBundleId Index of the root bundle that needs to be deleted. Note: this is intentionally a uint256\n * to ensure that a small input range doesn't limit which indices this method is able to reach.\n */\n function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant {\n delete rootBundles[rootBundleId];\n emit EmergencyDeleteRootBundle(rootBundleId);\n }\n\n /**************************************\n * DEPOSITOR FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\n * tokens in this contract and receive a destination token on the destination chain. The origin => destination\n * token mapping is stored on the L1 HubPool.\n * @notice The caller must first approve this contract to spend amount of originToken.\n * @notice The originToken => destinationChainId must be enabled.\n * @notice This method is payable because the caller is able to deposit native token if the originToken is\n * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\n * @param recipient Address to receive funds at on destination chain.\n * @param originToken Token to lock into this contract to initiate deposit.\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n */\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) public payable override nonReentrant {\n // Check that deposit route is enabled.\n require(enabledDepositRoutes[originToken][destinationChainId], \"Disabled route\");\n\n // We limit the relay fees to prevent the user spending all their funds on fees.\n require(relayerFeePct < 0.5e18, \"invalid relayer fee\");\n // This function assumes that L2 timing cannot be compared accurately and consistently to L1 timing. Therefore,\n // block.timestamp is different from the L1 EVM's. Therefore, the quoteTimestamp must be within a configurable\n // buffer of this contract's block time to allow for this variance.\n // Note also that quoteTimestamp cannot be less than the buffer otherwise the following arithmetic can result\n // in underflow. This isn't a problem as the deposit will revert, but the error might be unexpected for clients.\n require(\n getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer &&\n getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer,\n \"invalid quote time\"\n );\n // If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the\n // transaction then the user is sending ETH. In this case, the ETH should be deposited to wrappedNativeToken.\n if (originToken == address(wrappedNativeToken) && msg.value > 0) {\n require(msg.value == amount, \"msg.value must match amount\");\n wrappedNativeToken.deposit{ value: msg.value }();\n // Else, it is a normal ERC20. In this case pull the token from the user's wallet as per normal.\n // Note: this includes the case where the L2 user has WETH (already wrapped ETH) and wants to bridge them.\n // In this case the msg.value will be set to 0, indicating a \"normal\" ERC20 bridging action.\n } else IERC20(originToken).safeTransferFrom(msg.sender, address(this), amount);\n\n _emitDeposit(\n amount,\n chainId(),\n destinationChainId,\n relayerFeePct,\n numberOfDeposits,\n quoteTimestamp,\n originToken,\n recipient,\n msg.sender\n );\n\n // Increment count of deposits so that deposit ID for this spoke pool is unique.\n // @dev: Use pre-increment to save gas:\n // i++ --> Load, Store, Add, Store\n // ++i --> Load, Add, Store\n ++numberOfDeposits;\n }\n\n /**\n * @notice Convenience method that depositor can use to signal to relayer to use updated fee.\n * @notice Relayer should only use events emitted by this function to submit fills with updated fees, otherwise they\n * risk their fills getting disputed for being invalid, for example if the depositor never actually signed the\n * update fee message.\n * @notice This function will revert if the depositor did not sign a message containing the updated fee for the\n * deposit ID stored in this contract. If the deposit ID is for another contract, or the depositor address is\n * incorrect, or the updated fee is incorrect, then the signature will not match and this function will revert.\n * @param depositor Signer of the update fee message who originally submitted the deposit. If the deposit doesn't\n * exist, then the relayer will not be able to fill any relay, so the caller should validate that the depositor\n * did in fact submit a relay.\n * @param newRelayerFeePct New relayer fee that relayers can use.\n * @param depositId Deposit to update fee for that originated in this contract.\n * @param depositorSignature Signed message containing the depositor address, this contract chain ID, the updated\n * relayer fee %, and the deposit ID. This signature is produced by signing a hash of data according to the\n * EIP-1271 standard. See more in the _verifyUpdateRelayerFeeMessage() comments.\n */\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n require(newRelayerFeePct < 0.5e18, \"invalid relayer fee\");\n\n _verifyUpdateRelayerFeeMessage(depositor, chainId(), newRelayerFeePct, depositId, depositorSignature);\n\n // Assuming the above checks passed, a relayer can take the signature and the updated relayer fee information\n // from the following event to submit a fill with an updated fee %.\n emit RequestedSpeedUpDeposit(newRelayerFeePct, depositId, depositor, depositorSignature);\n }\n\n /**************************************\n * RELAYER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Called by relayer to fulfill part of a deposit by sending destination tokens to the recipient.\n * Relayer is expected to pass in unique identifying information for deposit that they want to fulfill, and this\n * relay submission will be validated by off-chain data workers who can dispute this relay if any part is invalid.\n * If the relay is valid, then the relayer will be refunded on their desired repayment chain. If relay is invalid,\n * then relayer will not receive any refund.\n * @notice All of the deposit data can be found via on-chain events from the origin SpokePool, except for the\n * realizedLpFeePct which is a function of the HubPool's utilization at the deposit quote time. This fee %\n * is deterministic based on the quote time, so the relayer should just compute it using the canonical algorithm\n * as described in a UMIP linked to the HubPool's identifier.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Fee % to keep as relayer, specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n */\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) public nonReentrant {\n // Each relay attempt is mapped to the hash of data uniquely identifying it, which includes the deposit data\n // such as the origin chain ID and the deposit ID, and the data in a relay attempt such as who the recipient\n // is, which chain and currency the recipient wants to receive funds on, and the relay fees.\n SpokePoolInterface.RelayData memory relayData = SpokePoolInterface.RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, relayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, relayerFeePct, relayData, false);\n }\n\n /**\n * @notice Called by relayer to execute same logic as calling fillRelay except that relayer is using an updated\n * relayer fee %. The fee % must have been emitted in a message cryptographically signed by the depositor.\n * @notice By design, the depositor probably emitted the message with the updated fee by calling speedUpRelay().\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param maxTokensToSend Max amount of tokens to send recipient. If higher than amount, then caller will\n * send recipient the full relay amount.\n * @param repaymentChainId Chain of SpokePool where relayer wants to be refunded after the challenge window has\n * passed.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param newRelayerFeePct New fee % to keep as relayer also specified by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param depositorSignature Depositor-signed message containing updated fee %.\n */\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) public override nonReentrant {\n _verifyUpdateRelayerFeeMessage(depositor, originChainId, newRelayerFeePct, depositId, depositorSignature);\n\n // Now follow the default fillRelay flow with the updated fee and the original relay hash.\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId,\n originChainId: originChainId,\n destinationChainId: chainId()\n });\n bytes32 relayHash = _getRelayHash(relayData);\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, maxTokensToSend, newRelayerFeePct, false);\n\n _emitFillRelay(relayHash, fillAmountPreFees, repaymentChainId, newRelayerFeePct, relayData, false);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Executes a slow relay leaf stored as part of a root bundle. Will send the full amount remaining in the\n * relay to the recipient, less fees.\n * @dev This function assumes that the relay's destination chain ID is the current chain ID, which prevents\n * the caller from executing a slow relay intended for another chain on this chain.\n * @param depositor Depositor on origin chain who set this chain as the destination chain.\n * @param recipient Specified recipient on this chain.\n * @param destinationToken Token to send to recipient. Should be mapped to the origin token, origin chain ID\n * and this chain ID via a mapping on the HubPool.\n * @param amount Full size of the deposit.\n * @param originChainId Chain of SpokePool where deposit originated.\n * @param realizedLpFeePct Fee % based on L1 HubPool utilization at deposit quote time. Deterministic based on\n * quote time.\n * @param relayerFeePct Original fee % to keep as relayer set by depositor.\n * @param depositId Unique deposit ID on origin spoke pool.\n * @param rootBundleId Unique ID of root bundle containing slow relay root that this leaf is contained in.\n * @param proof Inclusion proof for this leaf in slow relay root in root bundle.\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n amount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Executes a relayer refund leaf stored as part of a root bundle. Will send the relayer the amount they\n * sent to the recipient plus a relayer fee.\n * @param rootBundleId Unique ID of root bundle containing relayer refund root that this leaf is contained in.\n * @param relayerRefundLeaf Contains all data necessary to reconstruct leaf contained in root bundle and to\n * refund relayer. This data structure is explained in detail in the SpokePoolInterface.\n * @param proof Inclusion proof for this leaf in relayer refund root in root bundle.\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public virtual override nonReentrant {\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * VIEW FUNCTIONS *\n **************************************/\n\n /**\n * @notice Returns chain ID for this network.\n * @dev Some L2s like ZKSync don't support the CHAIN_ID opcode so we allow the implementer to override this.\n */\n function chainId() public view virtual override returns (uint256) {\n return block.chainid;\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Verifies inclusion proof of leaf in root, sends relayer their refund, and sends to HubPool any rebalance\n // transfers.\n function _executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) internal {\n // Check integrity of leaf structure:\n require(relayerRefundLeaf.chainId == chainId(), \"Invalid chainId\");\n require(relayerRefundLeaf.refundAddresses.length == relayerRefundLeaf.refundAmounts.length, \"invalid leaf\");\n\n RootBundle storage rootBundle = rootBundles[rootBundleId];\n\n // Check that inclusionProof proves that relayerRefundLeaf is contained within the relayer refund root.\n // Note: This should revert if the relayerRefundRoot is uninitialized.\n require(MerkleLib.verifyRelayerRefund(rootBundle.relayerRefundRoot, relayerRefundLeaf, proof), \"Bad Proof\");\n\n // Verify the leafId in the leaf has not yet been claimed.\n require(!MerkleLib.isClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId), \"Already claimed\");\n\n // Set leaf as claimed in bitmap. This is passed by reference to the storage rootBundle.\n MerkleLib.setClaimed(rootBundle.claimedBitmap, relayerRefundLeaf.leafId);\n\n // Send each relayer refund address the associated refundAmount for the L2 token address.\n // Note: Even if the L2 token is not enabled on this spoke pool, we should still refund relayers.\n uint256 length = relayerRefundLeaf.refundAmounts.length;\n for (uint256 i = 0; i < length; ) {\n uint256 amount = relayerRefundLeaf.refundAmounts[i];\n if (amount > 0)\n IERC20(relayerRefundLeaf.l2TokenAddress).safeTransfer(relayerRefundLeaf.refundAddresses[i], amount);\n\n // OK because we assume refund array length won't be > types(uint256).max.\n // Based on the stress test results in /test/gas-analytics/SpokePool.RelayerRefundLeaf.ts, the UMIP should\n // limit the refund count in valid proposals to be ~800 so any RelayerRefundLeaves with > 800 refunds should\n // not make it to this stage.\n\n unchecked {\n ++i;\n }\n }\n\n // If leaf's amountToReturn is positive, then send L2 --> L1 message to bridge tokens back via\n // chain-specific bridging method.\n if (relayerRefundLeaf.amountToReturn > 0) {\n _bridgeTokensToHubPool(relayerRefundLeaf);\n\n emit TokensBridged(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n msg.sender\n );\n }\n\n emit ExecutedRelayerRefundRoot(\n relayerRefundLeaf.amountToReturn,\n relayerRefundLeaf.chainId,\n relayerRefundLeaf.refundAmounts,\n rootBundleId,\n relayerRefundLeaf.leafId,\n relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.refundAddresses,\n msg.sender\n );\n }\n\n // Verifies inclusion proof of leaf in root and sends recipient remainder of relay. Marks relay as filled.\n function _executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) internal {\n RelayData memory relayData = RelayData({\n depositor: depositor,\n recipient: recipient,\n destinationToken: destinationToken,\n amount: amount,\n originChainId: originChainId,\n destinationChainId: destinationChainId,\n realizedLpFeePct: realizedLpFeePct,\n relayerFeePct: relayerFeePct,\n depositId: depositId\n });\n\n require(\n MerkleLib.verifySlowRelayFulfillment(rootBundles[rootBundleId].slowRelayRoot, relayData, proof),\n \"Invalid proof\"\n );\n\n bytes32 relayHash = _getRelayHash(relayData);\n\n // Note: use relayAmount as the max amount to send, so the relay is always completely filled by the contract's\n // funds in all cases. As this is a slow relay we set the relayerFeePct to 0. This effectively refunds the\n // relayer component of the relayerFee thereby only charging the depositor the LpFee.\n uint256 fillAmountPreFees = _fillRelay(relayHash, relayData, relayData.amount, 0, true);\n\n // Note: Set repayment chain ID to 0 to indicate that there is no repayment to be made. The off-chain data\n // worker can use repaymentChainId=0 as a signal to ignore such relays for refunds. Also, set the relayerFeePct\n // to 0 as slow relays do not pay the caller of this method (depositor is refunded this fee).\n _emitFillRelay(relayHash, fillAmountPreFees, 0, 0, relayData, true);\n }\n\n function _setCrossDomainAdmin(address newCrossDomainAdmin) internal {\n require(newCrossDomainAdmin != address(0), \"Bad bridge router address\");\n crossDomainAdmin = newCrossDomainAdmin;\n emit SetXDomainAdmin(newCrossDomainAdmin);\n }\n\n function _setHubPool(address newHubPool) internal {\n require(newHubPool != address(0), \"Bad hub pool address\");\n hubPool = newHubPool;\n emit SetHubPool(newHubPool);\n }\n\n // Should be overriden by implementing contract depending on how L2 handles sending tokens to L1.\n function _bridgeTokensToHubPool(SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf) internal virtual;\n\n function _verifyUpdateRelayerFeeMessage(\n address depositor,\n uint256 originChainId,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) internal view {\n // A depositor can request to speed up an un-relayed deposit by signing a hash containing the relayer\n // fee % to update to and information uniquely identifying the deposit to relay. This information ensures\n // that this signature cannot be re-used for other deposits. The version string is included as a precaution\n // in case this contract is upgraded.\n // Note: we use encode instead of encodePacked because it is more secure, more in the \"warning\" section\n // here: https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#non-standard-packed-mode\n bytes32 expectedDepositorMessageHash = keccak256(\n abi.encode(\"ACROSS-V2-FEE-1.0\", newRelayerFeePct, depositId, originChainId)\n );\n\n // Check the hash corresponding to the https://eth.wiki/json-rpc/API#eth_sign[eth_sign]\n // If the depositor signed a message with a different updated fee (or any other param included in the\n // above keccak156 hash), then this will revert.\n bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(expectedDepositorMessageHash);\n\n _verifyDepositorUpdateFeeMessage(depositor, ethSignedMessageHash, depositorSignature);\n }\n\n // This function is isolated and made virtual to allow different L2's to implement chain specific recovery of\n // signers from signatures because some L2s might not support ecrecover. To be safe, consider always reverting\n // this function for L2s where ecrecover is different from how it works on Ethereum, otherwise there is the\n // potential to forge a signature from the depositor using a different private key than the original depositor's.\n function _verifyDepositorUpdateFeeMessage(\n address depositor,\n bytes32 ethSignedMessageHash,\n bytes memory depositorSignature\n ) internal view virtual {\n // Note: We purposefully do not support EIP-1271 signatures (meaning that multisigs and smart contract wallets\n // like Argent are not supported) because of the possibility that a multisig that signed a message on the origin\n // chain does not have a parallel on this destination chain.\n require(depositor == ECDSA.recover(ethSignedMessageHash, depositorSignature), \"invalid signature\");\n }\n\n function _computeAmountPreFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (1e18 * amount) / (1e18 - feesPct);\n }\n\n function _computeAmountPostFees(uint256 amount, uint64 feesPct) private pure returns (uint256) {\n return (amount * (1e18 - feesPct)) / 1e18;\n }\n\n function _getRelayHash(SpokePoolInterface.RelayData memory relayData) private pure returns (bytes32) {\n return keccak256(abi.encode(relayData));\n }\n\n // Unwraps ETH and does a transfer to a recipient address. If the recipient is a smart contract then sends wrappedNativeToken.\n function _unwrapwrappedNativeTokenTo(address payable to, uint256 amount) internal {\n if (address(to).isContract()) {\n IERC20(address(wrappedNativeToken)).safeTransfer(to, amount);\n } else {\n wrappedNativeToken.withdraw(amount);\n to.transfer(amount);\n }\n }\n\n /**\n * @notice Caller specifies the max amount of tokens to send to user. Based on this amount and the amount of the\n * relay remaining (as stored in the relayFills mapping), pull the amount of tokens from the caller\n * and send to the recipient.\n * @dev relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n * numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n * fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n * @dev Caller must approve this contract to transfer up to maxTokensToSend of the relayData.destinationToken.\n * The amount to be sent might end up less if there is insufficient relay amount remaining to be sent.\n */\n function _fillRelay(\n bytes32 relayHash,\n RelayData memory relayData,\n uint256 maxTokensToSend,\n uint64 updatableRelayerFeePct,\n bool useContractFunds\n ) internal returns (uint256 fillAmountPreFees) {\n // We limit the relay fees to prevent the user spending all their funds on fees. Note that 0.5e18 (i.e. 50%)\n // fees are just magic numbers. The important point is to prevent the total fee from being 100%, otherwise\n // computing the amount pre fees runs into divide-by-0 issues.\n require(updatableRelayerFeePct < 0.5e18 && relayData.realizedLpFeePct < 0.5e18, \"invalid fees\");\n\n // Check that the relay has not already been completely filled. Note that the relays mapping will point to\n // the amount filled so far for a particular relayHash, so this will start at 0 and increment with each fill.\n require(relayFills[relayHash] < relayData.amount, \"relay filled\");\n\n // Stores the equivalent amount to be sent by the relayer before fees have been taken out.\n if (maxTokensToSend == 0) return 0;\n\n // Derive the amount of the relay filled if the caller wants to send exactly maxTokensToSend tokens to\n // the recipient. For example, if the user wants to send 10 tokens to the recipient, the full relay amount\n // is 100, and the fee %'s total 5%, then this computation would return ~10.5, meaning that to fill 10.5/100\n // of the full relay size, the caller would need to send 10 tokens to the user.\n fillAmountPreFees = _computeAmountPreFees(\n maxTokensToSend,\n (relayData.realizedLpFeePct + updatableRelayerFeePct)\n );\n // If user's specified max amount to send is greater than the amount of the relay remaining pre-fees,\n // we'll pull exactly enough tokens to complete the relay.\n uint256 amountToSend = maxTokensToSend;\n uint256 amountRemainingInRelay = relayData.amount - relayFills[relayHash];\n if (amountRemainingInRelay < fillAmountPreFees) {\n fillAmountPreFees = amountRemainingInRelay;\n\n // The user will fulfill the remainder of the relay, so we need to compute exactly how many tokens post-fees\n // that they need to send to the recipient. Note that if the relayer is filled using contract funds then\n // this is a slow relay.\n amountToSend = _computeAmountPostFees(\n fillAmountPreFees,\n relayData.realizedLpFeePct + updatableRelayerFeePct\n );\n }\n\n // relayFills keeps track of pre-fee fill amounts as a convenience to relayers who want to specify round\n // numbers for the maxTokensToSend parameter or convenient numbers like 100 (i.e. relayers who will fully\n // fill any relay up to 100 tokens, and partial fill with 100 tokens for larger relays).\n relayFills[relayHash] += fillAmountPreFees;\n\n // If relay token is wrappedNativeToken then unwrap and send native token.\n if (relayData.destinationToken == address(wrappedNativeToken)) {\n // Note: useContractFunds is True if we want to send funds to the recipient directly out of this contract,\n // otherwise we expect the caller to send funds to the recipient. If useContractFunds is True and the\n // recipient wants wrappedNativeToken, then we can assume that wrappedNativeToken is already in the\n // contract, otherwise we'll need the user to send wrappedNativeToken to this contract. Regardless, we'll\n // need to unwrap it to native token before sending to the user.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, address(this), amountToSend);\n _unwrapwrappedNativeTokenTo(payable(relayData.recipient), amountToSend);\n // Else, this is a normal ERC20 token. Send to recipient.\n } else {\n // Note: Similar to note above, send token directly from the contract to the user in the slow relay case.\n if (!useContractFunds)\n IERC20(relayData.destinationToken).safeTransferFrom(msg.sender, relayData.recipient, amountToSend);\n else IERC20(relayData.destinationToken).safeTransfer(relayData.recipient, amountToSend);\n }\n }\n\n // The following internal methods emit events with many params to overcome solidity stack too deep issues.\n function _emitFillRelay(\n bytes32 relayHash,\n uint256 fillAmount,\n uint256 repaymentChainId,\n uint64 appliedRelayerFeePct,\n RelayData memory relayData,\n bool isSlowRelay\n ) internal {\n emit FilledRelay(\n relayData.amount,\n relayFills[relayHash],\n fillAmount,\n repaymentChainId,\n relayData.originChainId,\n relayData.destinationChainId,\n relayData.relayerFeePct,\n appliedRelayerFeePct,\n relayData.realizedLpFeePct,\n relayData.depositId,\n relayData.destinationToken,\n msg.sender,\n relayData.depositor,\n relayData.recipient,\n isSlowRelay\n );\n }\n\n function _emitDeposit(\n uint256 amount,\n uint256 originChainId,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 quoteTimestamp,\n address originToken,\n address recipient,\n address depositor\n ) internal {\n emit FundsDeposited(\n amount,\n originChainId,\n destinationChainId,\n relayerFeePct,\n depositId,\n quoteTimestamp,\n originToken,\n recipient,\n depositor\n );\n }\n\n // Implementing contract needs to override this to ensure that only the appropriate cross chain admin can execute\n // certain admin functions. For L2 contracts, the cross chain admin refers to some L1 address or contract, and for\n // L1, this would just be the same admin of the HubPool.\n function _requireAdminSender() internal virtual;\n\n // Added to enable the this contract to receive native token (ETH). Used when unwrapping wrappedNativeToken.\n receive() external payable {}\n}\n" }, "contracts/SpokePoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Contains common data structures and functions used by all SpokePool implementations.\n */\ninterface SpokePoolInterface {\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\n struct RelayerRefundLeaf {\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\n // is negative. This is just the negative of this value.\n uint256 amountToReturn;\n // Used to verify that this is being executed on the correct destination chainId.\n uint256 chainId;\n // This array designates how much each of those addresses should be refunded.\n uint256[] refundAmounts;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint32 leafId;\n // The associated L2TokenAddress that these claims apply to.\n address l2TokenAddress;\n // Must be same length as refundAmounts and designates each address that must be refunded.\n address[] refundAddresses;\n }\n\n // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is\n // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be\n // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off\n // chain validator can choose when to refund slow relayers.\n struct RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // The corresponding token address on the destination chain.\n address destinationToken;\n // The total relay amount before fees are taken out.\n uint256 amount;\n // Origin chain id.\n uint256 originChainId;\n // Destination chain id.\n uint256 destinationChainId;\n // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp\n // and the HubPool's utilization.\n uint64 realizedLpFeePct;\n // The relayer fee percentage specified in the deposit.\n uint64 relayerFeePct;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n }\n\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\n // by \"data workers\" via inclusion proofs to execute leaves in the roots.\n struct RootBundle {\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\n bytes32 slowRelayRoot;\n // Merkle root of relayer refunds for successful relays.\n bytes32 relayerRefundRoot;\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\n // 256x(2^248) leaves per root.\n mapping(uint256 => uint256) claimedBitmap;\n }\n\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\n\n function setHubPool(address newHubPool) external;\n\n function setEnableRoute(\n address originToken,\n uint256 destinationChainId,\n bool enable\n ) external;\n\n function setDepositQuoteTimeBuffer(uint32 buffer) external;\n\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\n\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\n\n function deposit(\n address recipient,\n address originToken,\n uint256 amount,\n uint256 destinationChainId,\n uint64 relayerFeePct,\n uint32 quoteTimestamp\n ) external payable;\n\n function speedUpDeposit(\n address depositor,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function fillRelay(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId\n ) external;\n\n function fillRelayWithUpdatedFee(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 maxTokensToSend,\n uint256 repaymentChainId,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint64 newRelayerFeePct,\n uint32 depositId,\n bytes memory depositorSignature\n ) external;\n\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 amount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) external;\n\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) external;\n\n function chainId() external view returns (uint256);\n}\n" }, "contracts/MerkleLib.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePoolInterface.sol\";\nimport \"./HubPoolInterface.sol\";\n\nimport \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n/**\n * @notice Library to help with merkle roots, proofs, and claims.\n */\nlibrary MerkleLib {\n /**\n * @notice Verifies that a repayment is contained within a merkle root.\n * @param root the merkle root.\n * @param rebalance the rebalance struct.\n * @param proof the merkle proof.\n * @return bool to signal if the pool rebalance proof correctly shows inclusion of the rebalance within the tree.\n */\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(rebalance)));\n }\n\n /**\n * @notice Verifies that a relayer refund is contained within a merkle root.\n * @param root the merkle root.\n * @param refund the refund struct.\n * @param proof the merkle proof.\n * @return bool to signal if the relayer refund proof correctly shows inclusion of the refund within the tree.\n */\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(refund)));\n }\n\n /**\n * @notice Verifies that a distribution is contained within a merkle root.\n * @param root the merkle root.\n * @param slowRelayFulfillment the relayData fulfillment struct.\n * @param proof the merkle proof.\n * @return bool to signal if the slow relay's proof correctly shows inclusion of the slow relay within the tree.\n */\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) internal pure returns (bool) {\n return MerkleProof.verify(proof, root, keccak256(abi.encode(slowRelayFulfillment)));\n }\n\n // The following functions are primarily copied from\n // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes.\n\n /**\n * @notice Tests whether a claim is contained within a claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to check in the bitmap.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal view returns (bool) {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n uint256 claimedWord = claimedBitMap[claimedWordIndex];\n uint256 mask = (1 << claimedBitIndex);\n return claimedWord & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap.\n * @param index the index to mark in the bitmap.\n */\n function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) internal {\n uint256 claimedWordIndex = index / 256;\n uint256 claimedBitIndex = index % 256;\n claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);\n }\n\n /**\n * @notice Tests whether a claim is contained within a 1D claimedBitMap mapping.\n * @param claimedBitMap a simple uint256 value, encoding a 1D bitmap.\n * @param index the index to check in the bitmap. Uint8 type enforces that index can't be > 255.\n * @return bool indicating if the index within the claimedBitMap has been marked as claimed.\n */\n function isClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (bool) {\n uint256 mask = (1 << index);\n return claimedBitMap & mask == mask;\n }\n\n /**\n * @notice Marks an index in a claimedBitMap as claimed.\n * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. Uint8 type enforces that index\n * can't be > 255.\n * @param index the index to mark in the bitmap.\n * @return uint256 representing the modified input claimedBitMap with the index set to true.\n */\n function setClaimed1D(uint256 claimedBitMap, uint8 index) internal pure returns (uint256) {\n return claimedBitMap | (1 << index % 256);\n }\n}\n" }, "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" }, "@uma/core/contracts/common/implementation/Testable.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Timer.sol\";\n\n/**\n * @title Base class that provides time overrides, but only if being run in test mode.\n */\nabstract contract Testable {\n // If the contract is being run in production, then `timerAddress` will be the 0x0 address.\n // Note: this variable should be set on construction and never modified.\n address public timerAddress;\n\n /**\n * @notice Constructs the Testable contract. Called by child contracts.\n * @param _timerAddress Contract that stores the current time in a testing environment.\n * Must be set to 0x0 for production environments that use live time.\n */\n constructor(address _timerAddress) {\n timerAddress = _timerAddress;\n }\n\n /**\n * @notice Reverts if not running in test mode.\n */\n modifier onlyIfTest {\n require(timerAddress != address(0x0));\n _;\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set current Testable time to.\n */\n function setCurrentTime(uint256 time) external onlyIfTest {\n Timer(timerAddress).setCurrentTime(time);\n }\n\n /**\n * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.\n * Otherwise, it will return the block timestamp.\n * @return uint for the current Testable timestamp.\n */\n function getCurrentTime() public view virtual returns (uint256) {\n if (timerAddress != address(0x0)) {\n return Timer(timerAddress).getCurrentTime();\n } else {\n return block.timestamp; // solhint-disable-line not-rely-on-time\n }\n }\n}\n" }, "contracts/HubPoolInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Concise list of functions in HubPool implementation.\n */\ninterface HubPoolInterface {\n // This leaf is meant to be decoded in the HubPool to rebalance tokens between HubPool and SpokePool.\n struct PoolRebalanceLeaf {\n // This is used to know which chain to send cross-chain transactions to (and which SpokePool to send to).\n uint256 chainId;\n // Total LP fee amount per token in this bundle, encompassing all associated bundled relays.\n uint256[] bundleLpFees;\n // Represents the amount to push to or pull from the SpokePool. If +, the pool pays the SpokePool. If negative\n // the SpokePool pays the HubPool. There can be arbitrarily complex rebalancing rules defined offchain. This\n // number is only nonzero when the rules indicate that a rebalancing action should occur. When a rebalance does\n // occur, runningBalances must be set to zero for this token and netSendAmounts should be set to the previous\n // runningBalances + relays - deposits in this bundle. If non-zero then it must be set on the SpokePool's\n // RelayerRefundLeaf amountToReturn as -1 * this value to show if funds are being sent from or to the SpokePool.\n int256[] netSendAmounts;\n // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1\n // pool. A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that\n // the SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmounts.\n int256[] runningBalances;\n // Used by data worker to mark which leaves should relay roots to SpokePools, and to otherwise organize leaves.\n // For example, each leaf should contain all the rebalance information for a single chain, but in the case where\n // the list of l1Tokens is very large such that they all can't fit into a single leaf that can be executed under\n // the block gas limit, then the data worker can use this groupIndex to organize them. Any leaves with\n // a groupIndex equal to 0 will relay roots to the SpokePool, so the data worker should ensure that only one\n // leaf for a specific chainId should have a groupIndex equal to 0.\n uint256 groupIndex;\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\n uint8 leafId;\n // The bundleLpFees, netSendAmounts, and runningBalances are required to be the same length. They are parallel\n // arrays for the given chainId and should be ordered by the l1Tokens field. All whitelisted tokens with nonzero\n // relays on this chain in this bundle in the order of whitelisting.\n address[] l1Tokens;\n }\n\n // A data worker can optimistically store several merkle roots on this contract by staking a bond and calling\n // proposeRootBundle. By staking a bond, the data worker is alleging that the merkle roots all contain valid leaves\n // that can be executed later to:\n // - Send funds from this contract to a SpokePool or vice versa\n // - Send funds from a SpokePool to Relayer as a refund for a relayed deposit\n // - Send funds from a SpokePool to a deposit recipient to fulfill a \"slow\" relay\n // Anyone can dispute this struct if the merkle roots contain invalid leaves before the\n // challengePeriodEndTimestamp. Once the expiration timestamp is passed, executeRootBundle to execute a leaf\n // from the poolRebalanceRoot on this contract and it will simultaneously publish the relayerRefundRoot and\n // slowRelayRoot to a SpokePool. The latter two roots, once published to the SpokePool, contain\n // leaves that can be executed on the SpokePool to pay relayers or recipients.\n struct RootBundle {\n // Contains leaves instructing this contract to send funds to SpokePools.\n bytes32 poolRebalanceRoot;\n // Relayer refund merkle root to be published to a SpokePool.\n bytes32 relayerRefundRoot;\n // Slow relay merkle root to be published to a SpokePool.\n bytes32 slowRelayRoot;\n // This is a 1D bitmap, with max size of 256 elements, limiting us to 256 chainsIds.\n uint256 claimedBitMap;\n // Proposer of this root bundle.\n address proposer;\n // Number of pool rebalance leaves to execute in the poolRebalanceRoot. After this number\n // of leaves are executed, a new root bundle can be proposed\n uint8 unclaimedPoolRebalanceLeafCount;\n // When root bundle challenge period passes and this root bundle becomes executable.\n uint32 challengePeriodEndTimestamp;\n }\n\n // Each whitelisted L1 token has an associated pooledToken struct that contains all information used to track the\n // cumulative LP positions and if this token is enabled for deposits.\n struct PooledToken {\n // LP token given to LPs of a specific L1 token.\n address lpToken;\n // True if accepting new LP's.\n bool isEnabled;\n // Timestamp of last LP fee update.\n uint32 lastLpFeeUpdate;\n // Number of LP funds sent via pool rebalances to SpokePools and are expected to be sent\n // back later.\n int256 utilizedReserves;\n // Number of LP funds held in contract less utilized reserves.\n uint256 liquidReserves;\n // Number of LP funds reserved to pay out to LPs as fees.\n uint256 undistributedLpFees;\n }\n\n // Helper contracts to facilitate cross chain actions between HubPool and SpokePool for a specific network.\n struct CrossChainContract {\n address adapter;\n address spokePool;\n }\n\n function setPaused(bool pause) external;\n\n function emergencyDeleteProposal() external;\n\n function relaySpokePoolAdminFunction(uint256 chainId, bytes memory functionData) external;\n\n function setProtocolFeeCapture(address newProtocolFeeCaptureAddress, uint256 newProtocolFeeCapturePct) external;\n\n function setBond(IERC20 newBondToken, uint256 newBondAmount) external;\n\n function setLiveness(uint32 newLiveness) external;\n\n function setIdentifier(bytes32 newIdentifier) external;\n\n function setCrossChainContracts(\n uint256 l2ChainId,\n address adapter,\n address spokePool\n ) external;\n\n function enableL1TokenForLiquidityProvision(address l1Token) external;\n\n function disableL1TokenForLiquidityProvision(address l1Token) external;\n\n function addLiquidity(address l1Token, uint256 l1TokenAmount) external payable;\n\n function removeLiquidity(\n address l1Token,\n uint256 lpTokenAmount,\n bool sendEth\n ) external;\n\n function exchangeRateCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationCurrent(address l1Token) external returns (uint256);\n\n function liquidityUtilizationPostRelay(address l1Token, uint256 relayedAmount) external returns (uint256);\n\n function sync(address l1Token) external;\n\n function proposeRootBundle(\n uint256[] memory bundleEvaluationBlockNumbers,\n uint8 poolRebalanceLeafCount,\n bytes32 poolRebalanceRoot,\n bytes32 relayerRefundRoot,\n bytes32 slowRelayRoot\n ) external;\n\n function executeRootBundle(\n uint256 chainId,\n uint256 groupIndex,\n uint256[] memory bundleLpFees,\n int256[] memory netSendAmounts,\n int256[] memory runningBalances,\n uint8 leafId,\n address[] memory l1Tokens,\n bytes32[] memory proof\n ) external;\n\n function disputeRootBundle() external;\n\n function claimProtocolFeesCaptured(address l1Token) external;\n\n function setPoolRebalanceRoute(\n uint256 destinationChainId,\n address l1Token,\n address destinationToken\n ) external;\n\n function setDepositRoute(\n uint256 originChainId,\n uint256 destinationChainId,\n address originToken,\n bool depositsEnabled\n ) external;\n\n function poolRebalanceRoute(uint256 destinationChainId, address l1Token)\n external\n view\n returns (address destinationToken);\n\n function loadEthForL2Calls() external payable;\n}\n" }, "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The proofs can be generated using the JavaScript library\n * https://github.com/miguelmota/merkletreejs[merkletreejs].\n * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.\n *\n * See `test/utils/cryptography/MerkleProof.test.js` for some examples.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n */\nlibrary MerkleProof {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,\n * consuming from one or the other at each step according to the instructions given by\n * `proofFlags`.\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" }, "contracts/interfaces/AdapterInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @notice Sends cross chain messages and tokens to contracts on a specific L2 network.\n */\n\ninterface AdapterInterface {\n event MessageRelayed(address target, bytes message);\n\n event TokensRelayed(address l1Token, address l2Token, uint256 amount, address to);\n\n function relayMessage(address target, bytes calldata message) external payable;\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable;\n}\n" }, "@openzeppelin/contracts/utils/Strings.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" }, "@uma/core/contracts/common/implementation/Timer.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Universal store of current contract time for testing environments.\n */\ncontract Timer {\n uint256 private currentTime;\n\n constructor() {\n currentTime = block.timestamp; // solhint-disable-line not-rely-on-time\n }\n\n /**\n * @notice Sets the current time.\n * @dev Will revert if not running in test mode.\n * @param time timestamp to set `currentTime` to.\n */\n function setCurrentTime(uint256 time) external {\n currentTime = time;\n }\n\n /**\n * @notice Gets the currentTime variable set in the Timer.\n * @return uint256 for the current Testable timestamp.\n */\n function getCurrentTime() public view returns (uint256) {\n return currentTime;\n }\n}\n" }, "contracts/test/MockSpokePool.sol": { "content": "//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"../SpokePool.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @title MockSpokePool\n * @notice Implements abstract contract for testing.\n */\ncontract MockSpokePool is SpokePool {\n uint256 private chainId_;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks\n\n // solhint-disable-next-line no-empty-blocks\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {}\n\n function _requireAdminSender() internal override {} // solhint-disable-line no-empty-blocks\n\n function chainId() public view override(SpokePool) returns (uint256) {\n // If chainId_ is set then return it, else do nothing and return the parent chainId().\n return chainId_ == 0 ? super.chainId() : chainId_;\n }\n\n function setChainId(uint256 _chainId) public {\n chainId_ = _chainId;\n }\n}\n" }, "contracts/ZkSync_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface ZkBridgeLike {\n function withdraw(\n address _to,\n address _l2Token,\n uint256 _amount\n ) external;\n}\n\n/**\n * @notice ZkSync specific SpokePool, intended to be compiled with `@matterlabs/hardhat-zksync-solc`.\n */\ncontract ZkSync_SpokePool is SpokePool {\n // On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas cost\n // upon contract deployment. On zkSync the opposite is true: deploying the same bytecode for contracts,\n // while changing only constructor parameters can lead to substantial fee savings. So, the following params\n // are all set by passing in constructor params where possible.\n\n // However, this contract is expected to be deployed only once to ZkSync. Therefore, we should consider the cost\n // of reading mutable vs immutable storage. On Ethereum, mutable storage is more expensive than immutable bytecode.\n // But, we also want to be able to upgrade certain state variables.\n\n // Bridge used to withdraw ERC20's to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ERC20Bridge.sol\n ZkBridgeLike public zkErc20Bridge;\n\n // Bridge used to send ETH to L1: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol\n ZkBridgeLike public zkEthBridge;\n\n event SetZkBridges(address indexed erc20Bridge, address indexed ethBridge);\n event ZkSyncTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged);\n\n /**\n * @notice Construct the ZkSync SpokePool.\n * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin.\n * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n ZkBridgeLike _zkErc20Bridge,\n ZkBridgeLike _zkEthBridge,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n // Formal msg.sender of L1 --> L2 message will be L1 sender.\n require(msg.sender == crossDomainAdmin, \"Invalid sender\");\n _;\n }\n\n /**\n * @notice Returns chain ID for this network.\n * @dev ZKSync doesn't yet support the CHAIN_ID opcode so we override this, but it will be supported by mainnet\n * launch supposedly: https://v2-docs.zksync.io/dev/zksync-v2/temp-limits.html#temporarily-simulated-by-constant-values\n */\n function chainId() public pure override returns (uint256) {\n return 280;\n }\n\n /********************************************************\n * ZKSYNC-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 token bridge addresses. Callable only by admin.\n * @param _zkErc20Bridge New address of L2 ERC20 gateway.\n * @param _zkEthBridge New address of L2 ETH gateway.\n */\n function setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) public onlyAdmin nonReentrant {\n _setZkBridges(_zkErc20Bridge, _zkEthBridge);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken) ? zkEthBridge : zkErc20Bridge).withdraw(\n hubPool,\n // Note: If ETH, must use 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l2/contracts/bridge/L2ETHBridge.sol#L57\n relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)\n ? address(0)\n : relayerRefundLeaf.l2TokenAddress,\n relayerRefundLeaf.amountToReturn\n );\n\n emit ZkSyncTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setZkBridges(ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge) internal {\n zkErc20Bridge = _zkErc20Bridge;\n zkEthBridge = _zkEthBridge;\n emit SetZkBridges(address(_zkErc20Bridge), address(_zkEthBridge));\n }\n\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/Ethereum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @notice Ethereum L1 specific SpokePool. Used on Ethereum L1 to facilitate L2->L1 transfers.\n */\ncontract Ethereum_SpokePool is SpokePool, Ownable {\n /**\n * @notice Construct the Ethereum SpokePool.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(msg.sender, _hubPool, _wethAddress, timerAddress) {}\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n IERC20(relayerRefundLeaf.l2TokenAddress).transfer(hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n // Admin is simply owner which should be same account that owns the HubPool deployed on this network. A core\n // assumption of this contract system is that the HubPool is deployed on Ethereum.\n function _requireAdminSender() internal override onlyOwner {}\n}\n" }, "contracts/Ovm_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\nimport \"./interfaces/WETH9.sol\";\n\nimport \"@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\nimport \"@eth-optimism/contracts/L2/messaging/IL2ERC20Bridge.sol\";\n\n/**\n * @notice OVM specific SpokePool. Uses OVM cross-domain-enabled logic to implement admin only access to functions. * Optimism and Boba each implement this spoke pool and set their chain specific contract addresses for l2Eth and l2Weth.\n */\ncontract Ovm_SpokePool is CrossDomainEnabled, SpokePool {\n // \"l1Gas\" parameter used in call to bridge tokens from this contract back to L1 via IL2ERC20Bridge. Currently\n // unused by bridge but included for future compatibility.\n uint32 public l1Gas = 5_000_000;\n\n // ETH is an ERC20 on OVM.\n address public immutable l2Eth;\n\n // Stores alternative token bridges to use for L2 tokens that don't go over the standard bridge. This is needed\n // to support non-standard ERC20 tokens on Optimism, such as DIA and SNX which both use custom bridges.\n mapping(address => address) public tokenBridges;\n\n event OptimismTokensBridged(address indexed l2Token, address target, uint256 numberOfTokensBridged, uint256 l1Gas);\n event SetL1Gas(uint32 indexed newL1Gas);\n event SetL2TokenBridge(address indexed l2Token, address indexed tokenBridge);\n\n /**\n * @notice Construct the OVM SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address _l2Eth,\n address _wrappedNativeToken,\n address timerAddress\n )\n CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)\n SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress)\n {\n l2Eth = _l2Eth;\n }\n\n /*******************************************\n * OPTIMISM-SPECIFIC ADMIN FUNCTIONS *\n *******************************************/\n\n /**\n * @notice Change L1 gas limit. Callable only by admin.\n * @param newl1Gas New L1 gas limit to set.\n */\n function setL1GasLimit(uint32 newl1Gas) public onlyAdmin nonReentrant {\n l1Gas = newl1Gas;\n emit SetL1Gas(newl1Gas);\n }\n\n /**\n * @notice Set bridge contract for L2 token used to withdraw back to L1.\n * @dev If this mapping isn't set for an L2 token, then the standard bridge will be used to bridge this token.\n * @param tokenBridge Address of token bridge\n */\n function setTokenBridge(address l2Token, address tokenBridge) public onlyAdmin nonReentrant {\n tokenBridges[l2Token] = tokenBridge;\n emit SetL2TokenBridge(l2Token, tokenBridge);\n }\n\n /**************************************\n * DATA WORKER FUNCTIONS *\n **************************************/\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeSlowRelayLeaf(\n address depositor,\n address recipient,\n address destinationToken,\n uint256 totalRelayAmount,\n uint256 originChainId,\n uint64 realizedLpFeePct,\n uint64 relayerFeePct,\n uint32 depositId,\n uint32 rootBundleId,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (destinationToken == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeSlowRelayLeaf(\n depositor,\n recipient,\n destinationToken,\n totalRelayAmount,\n originChainId,\n chainId(),\n realizedLpFeePct,\n relayerFeePct,\n depositId,\n rootBundleId,\n proof\n );\n }\n\n /**\n * @notice Wraps any ETH into WETH before executing base function. This is necessary because SpokePool receives\n * ETH over the canonical token bridge instead of WETH.\n * @inheritdoc SpokePool\n */\n function executeRelayerRefundLeaf(\n uint32 rootBundleId,\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\n bytes32[] memory proof\n ) public override(SpokePool) nonReentrant {\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) _depositEthToWeth();\n\n _executeRelayerRefundLeaf(rootBundleId, relayerRefundLeaf, proof);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n // Wrap any ETH owned by this contract so we can send expected L2 token to recipient. This is necessary because\n // this SpokePool will receive ETH from the canonical token bridge instead of WETH. Its not sufficient to execute\n // this logic inside a fallback method that executes when this contract receives ETH because ETH is an ERC20\n // on the OVM.\n function _depositEthToWeth() internal {\n if (address(this).balance > 0) wrappedNativeToken.deposit{ value: address(this).balance }();\n }\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // If the token being bridged is WETH then we need to first unwrap it to ETH and then send ETH over the\n // canonical bridge. On Optimism, this is address 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.\n if (relayerRefundLeaf.l2TokenAddress == address(wrappedNativeToken)) {\n WETH9(relayerRefundLeaf.l2TokenAddress).withdraw(relayerRefundLeaf.amountToReturn); // Unwrap into ETH.\n relayerRefundLeaf.l2TokenAddress = l2Eth; // Set the l2TokenAddress to ETH.\n }\n IL2ERC20Bridge(\n tokenBridges[relayerRefundLeaf.l2TokenAddress] == address(0)\n ? Lib_PredeployAddresses.L2_STANDARD_BRIDGE\n : tokenBridges[relayerRefundLeaf.l2TokenAddress]\n ).withdrawTo(\n relayerRefundLeaf.l2TokenAddress, // _l2Token. Address of the L2 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n l1Gas, // _l1Gas. Unused, but included for potential forward compatibility considerations\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n\n emit OptimismTokensBridged(relayerRefundLeaf.l2TokenAddress, hubPool, relayerRefundLeaf.amountToReturn, l1Gas);\n }\n\n // Apply OVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAccount(crossDomainAdmin) {}\n}\n" }, "@eth-optimism/contracts/libraries/bridge/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n /*************\n * Variables *\n *************/\n\n // Messenger contract used to send and recieve messages from the other domain.\n address public messenger;\n\n /***************\n * Constructor *\n ***************/\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**********************\n * Function Modifiers *\n **********************/\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(\n msg.sender == address(getCrossDomainMessenger()),\n \"OVM_XCHAIN: messenger contract unauthenticated\"\n );\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"OVM_XCHAIN: wrong sender of cross-domain message\"\n );\n\n _;\n }\n\n /**********************\n * Internal Functions *\n **********************/\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**q\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * `onlyFromCrossDomainAccount()`)\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes memory _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" @@ -110,13 +110,13 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n /**********\n * Events *\n **********/\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n event RelayedMessage(bytes32 indexed msgHash);\n event FailedRelayedMessage(bytes32 indexed msgHash);\n\n /*************\n * Variables *\n *************/\n\n function xDomainMessageSender() external view returns (address);\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * Sends a cross domain message to the target messenger.\n * @param _target Target contract address.\n * @param _message Message to send to the target.\n * @param _gasLimit Gas limit for the provided message.\n */\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" }, "contracts/Optimism_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\nimport \"@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol\";\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Optimism Spoke pool.\n */\ncontract Optimism_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Optimism SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n Lib_PredeployAddresses.OVM_ETH,\n 0x4200000000000000000000000000000000000006,\n timerAddress\n )\n {}\n}\n" }, "contracts/chain-adapters/CrossDomainEnabled.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications between L1 and Optimism.\n * @dev This modifies the eth-optimism/CrossDomainEnabled contract only by changing state variables to be\n * immutable for use in contracts like the Optimism_Adapter which use delegateCall().\n */\ncontract CrossDomainEnabled {\n // Messenger contract used to send and recieve messages from the other domain.\n address public immutable messenger;\n\n /**\n * @param _messenger Address of the CrossDomainMessenger on the current layer.\n */\n constructor(address _messenger) {\n messenger = _messenger;\n }\n\n /**\n * Enforces that the modified function is only callable by a specific cross-domain account.\n * @param _sourceDomainAccount The only account on the originating domain which is\n * authenticated to call this function.\n */\n modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n require(msg.sender == address(getCrossDomainMessenger()), \"invalid cross domain messenger\");\n\n require(\n getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n \"invalid cross domain sender\"\n );\n\n _;\n }\n\n /**\n * Gets the messenger, usually from storage. This function is exposed in case a child contract\n * needs to override.\n * @return The address of the cross-domain messenger contract which should be used.\n */\n function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n return ICrossDomainMessenger(messenger);\n }\n\n /**\n * Sends a message to an account on another domain\n * @param _crossDomainTarget The intended recipient on the destination domain\n * @param _message The data to send to the target (usually calldata to a function with\n * onlyFromCrossDomainAccount())\n * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n */\n function sendCrossDomainMessage(\n address _crossDomainTarget,\n uint32 _gasLimit,\n bytes calldata _message\n ) internal {\n // slither-disable-next-line reentrancy-events, reentrancy-benign\n getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n }\n}\n" }, "contracts/chain-adapters/Optimism_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Optimism.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Optimism_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n // Optimism has the ability to support \"custom\" bridges. These bridges are not supported by the canonical bridge\n // and so we need to store the address of the custom token and the associated bridge. In the event we want to\n // support a new token that is not supported by Optimism, we can add a new custom bridge for it and re-deploy the\n // adapter. A full list of custom optimism tokens and their associated bridges can be found here:\n // https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json\n address public immutable dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n address public immutable daiOptimismBridge = 0x10E6593CDda8c58a1d0f14C5164B376352a55f2F;\n address public immutable snx = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F;\n address public immutable snxOptimismBridge = 0xCd9D4988C0AE61887B075bA77f08cbFAd2b65068;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Optimism system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Optimism.\n * @param target Contract on Optimism that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Optimism.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n // Check if the L1 token requires a custom bridge. If so, use that bridge over the standard bridge.\n if (l1Token == dai) _l1StandardBridge = IL1StandardBridge(daiOptimismBridge); // 1. DAI\n if (l1Token == snx) _l1StandardBridge = IL1StandardBridge(snxOptimismBridge); // 2. SNX\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\nimport \"./IL1ERC20Bridge.sol\";\n\n/**\n * @title IL1StandardBridge\n */\ninterface IL1StandardBridge is IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n event ETHDepositInitiated(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n event ETHWithdrawalFinalized(\n address indexed _from,\n address indexed _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev Deposit an amount of the ETH to the caller's balance on L2.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;\n\n /**\n * @dev Deposit an amount of ETH to a recipient's balance on L2.\n * @param _to L2 address to credit the withdrawal to.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositETHTo(\n address _to,\n uint32 _l2Gas,\n bytes calldata _data\n ) external payable;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called\n * before the withdrawal is finalized.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeETHWithdrawal(\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" @@ -125,58 +125,58 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title IL1ERC20Bridge\n */\ninterface IL1ERC20Bridge {\n /**********\n * Events *\n **********/\n\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /********************\n * Public Functions *\n ********************/\n\n /**\n * @dev get the address of the corresponding L2 bridge contract.\n * @return Address of the corresponding L2 bridge contract.\n */\n function l2TokenBridge() external returns (address);\n\n /**\n * @dev deposit an amount of the ERC20 to the caller's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _amount Amount of the ERC20 to deposit\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20(\n address _l1Token,\n address _l2Token,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /**\n * @dev deposit an amount of ERC20 to a recipient's balance on L2.\n * @param _l1Token Address of the L1 ERC20 we are depositing\n * @param _l2Token Address of the L1 respective L2 ERC20\n * @param _to L2 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _l2Gas Gas limit required to complete the deposit on L2.\n * @param _data Optional data to forward to L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function depositERC20To(\n address _l1Token,\n address _l2Token,\n address _to,\n uint256 _amount,\n uint32 _l2Gas,\n bytes calldata _data\n ) external;\n\n /*************************\n * Cross-chain Functions *\n *************************/\n\n /**\n * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n * L1 ERC20 token.\n * This call will fail if the initialized withdrawal from L2 has not been finalized.\n *\n * @param _l1Token Address of L1 token to finalizeWithdrawal for.\n * @param _l2Token Address of L2 token where withdrawal was initiated.\n * @param _from L2 address initiating the transfer.\n * @param _to L1 address to credit the withdrawal to.\n * @param _amount Amount of the ERC20 to deposit.\n * @param _data Data provided by the sender on L2. This data is provided\n * solely as a convenience for external contracts. Aside from enforcing a maximum\n * length, these contracts provide no guarantees about its content.\n */\n function finalizeERC20Withdrawal(\n address _l1Token,\n address _l2Token,\n address _from,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external;\n}\n" }, "contracts/chain-adapters/Boba_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\n// @dev Use local modified CrossDomainEnabled contract instead of one exported by eth-optimism because we need\n// this contract's state variables to be `immutable` because of the delegateCall call.\nimport \"./CrossDomainEnabled.sol\";\nimport \"@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Boba. This is a modified version of the Optimism adapter\n * that excludes the custom bridging logic.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Boba_Adapter is CrossDomainEnabled, AdapterInterface {\n using SafeERC20 for IERC20;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n WETH9 public immutable l1Weth;\n\n IL1StandardBridge public immutable l1StandardBridge;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1Weth WETH address on L1.\n * @param _crossDomainMessenger XDomainMessenger Boba system contract.\n * @param _l1StandardBridge Standard bridge contract.\n */\n constructor(\n WETH9 _l1Weth,\n address _crossDomainMessenger,\n IL1StandardBridge _l1StandardBridge\n ) CrossDomainEnabled(_crossDomainMessenger) {\n l1Weth = _l1Weth;\n l1StandardBridge = _l1StandardBridge;\n }\n\n /**\n * @notice Send cross-chain message to target on Boba.\n * @param target Contract on Boba that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n sendCrossDomainMessage(target, uint32(l2GasLimit), message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Boba.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n l1StandardBridge.depositETHTo{ value: amount }(to, l2GasLimit, \"\");\n } else {\n IL1StandardBridge _l1StandardBridge = l1StandardBridge;\n\n IERC20(l1Token).safeIncreaseAllowance(address(_l1StandardBridge), amount);\n _l1StandardBridge.depositERC20To(l1Token, l2Token, to, amount, l2GasLimit, \"\");\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/ZkSync_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Importing `Operations` contract which has the `QueueType` type\nimport \"@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol\";\n\ninterface ZkSyncLike {\n function requestL2Transaction(\n address _contractAddressL2,\n bytes calldata _calldata,\n uint256 _ergsLimit,\n bytes[] calldata _factoryDeps,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\ninterface ZkBridgeLike {\n function deposit(\n address _to,\n address _l1Token,\n uint256 _amount,\n QueueType _queueType\n ) external payable returns (bytes32 txHash);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to ZkSync.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract ZkSync_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // We need to pay a fee to submit transactions to the L1 --> L2 priority queue:\n // https://v2-docs.zksync.io/dev/zksync-v2/l1-l2-interop.html#priority-queue\n\n // The fee for a transactionis equal to `txBaseCost * gasPrice` where `txBaseCost` depends on the ergsLimit\n // (ergs = gas on ZkSync) and the calldata length. More details here:\n // https://v2-docs.zksync.io/dev/guide/l1-l2.html#using-contract-interface-in-your-project\n\n // Generally, the ergsLimit and l2GasPrice params are a bit hard to set and may change in the future once ZkSync\n // is deployed to mainnet. On testnet, gas price is set to 0 and gas used is 0 so its hard to accurately forecast.\n uint256 public immutable l2GasPrice = 1e9;\n\n uint32 public immutable ergsLimit = 1_000_000;\n\n // Hardcode WETH address for L1 since it will not change:\n WETH9 public immutable l1Weth = WETH9(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);\n\n // Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be\n // redeployed in the event that the following addresses change.\n\n // Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.\n ZkSyncLike public immutable zkSync = ZkSyncLike(0xa0F968EbA6Bbd08F28Dc061C7856C15725983395);\n // Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.\n ZkBridgeLike public immutable zkErc20Bridge = ZkBridgeLike(0x7786255495348c08F82C09C82352019fAdE3BF29);\n ZkBridgeLike public immutable zkEthBridge = ZkBridgeLike(0xcbebcD41CeaBBC85Da9bb67527F58d69aD4DfFf5);\n\n event ZkSyncMessageRelayed(bytes32 txHash);\n\n /**\n * @notice Send cross-chain message to target on ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message, or the message\n * will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // Parameters passed to requestL2Transaction:\n // _contractAddressL2 is a parameter that defines the address of the contract to be called.\n // _calldata is a parameter that contains the calldata of the transaction call. It can be encoded the\n // same way as on Ethereum.\n // _ergsLimit is a parameter that contains the ergs limit of the transaction call. You can learn more about\n // ergs and the zkSync fee system here: https://v2-docs.zksync.io/dev/zksync-v2/fee-model.html\n // _factoryDeps is a list of bytecodes. It should contain the bytecode of the contract being deployed.\n // If the contract being deployed is a factory contract, i.e. it can deploy other contracts, the array should also contain the bytecodes of the contracts that can be deployed by it.\n // _queueType is a parameter required for the priority mode functionality. For the testnet,\n // QueueType.Deque should always be supplied.\n bytes32 txHash = zkSync.requestL2Transaction{ value: txBaseCost }(\n target,\n message,\n ergsLimit,\n new bytes[](0),\n QueueType.Deque\n );\n\n emit MessageRelayed(target, message);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Bridge tokens to ZkSync.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message\n * or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused.\n uint256 amount,\n address to\n ) external payable override {\n uint256 txBaseCost = _contractHasSufficientEthBalance();\n\n // If the l1Token is WETH then unwrap it to ETH then send the ETH to the standard bridge along with the base\n // cost.\n bytes32 txHash;\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n // Must set L1Token address to 0x0: https://github.com/matter-labs/v2-testnet-contracts/blob/3a0651357bb685751c2163e4cc65a240b0f602ef/l1/contracts/bridge/L1EthBridge.sol#L78\n txHash = zkEthBridge.deposit{ value: txBaseCost + amount }(to, address(0), amount, QueueType.Deque);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(address(zkErc20Bridge), amount);\n txHash = zkErc20Bridge.deposit{ value: txBaseCost }(to, l1Token, amount, QueueType.Deque);\n }\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n emit ZkSyncMessageRelayed(txHash);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2GasPrice * ergsLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "@matterlabs/zksync-contracts/l1/contracts/zksync/Operations.sol": { "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n\n\n/// @notice Priority Operation container\n/// @param canonicalTxHash Hashed priority operation data that is needed to process the operation\n/// @param expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)\n/// @param layer2Tip Additional payment to the operator as an incentive to perform the operation\nstruct PriorityOperation {\n bytes32 canonicalTxHash;\n uint64 expirationBlock;\n uint192 layer2Tip;\n}\n\n/// @notice A structure that stores all priority operations by ID\n/// used for easy acceptance as an argument in functions\nstruct StoredOperations {\n mapping(uint64 => PriorityOperation) inner;\n}\n\n/// @notice Indicator that the operation can interact with Rollup and Porter trees, or only with Rollup\nenum OpTree {\n Full,\n Rollup\n}\n\n/// @notice Priority operations queue type\nenum QueueType {\n Deque,\n HeapBuffer,\n Heap\n}\n" }, "contracts/chain-adapters/Polygon_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"../interfaces/WETH9.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IRootChainManager {\n function depositEtherFor(address user) external payable;\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external;\n}\n\ninterface IFxStateSender {\n function sendMessageToChild(address _receiver, bytes calldata _data) external;\n}\n\ninterface DepositManager {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount\n ) external;\n}\n\n/**\n * @notice Sends cross chain messages Polygon L2 network.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Polygon_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n IRootChainManager public immutable rootChainManager;\n IFxStateSender public immutable fxStateSender;\n DepositManager public immutable depositManager;\n address public immutable erc20Predicate;\n address public immutable l1Matic;\n WETH9 public immutable l1Weth;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rootChainManager RootChainManager Polygon system contract to deposit tokens over the PoS bridge.\n * @param _fxStateSender FxStateSender Polygon system contract to send arbitrary messages to L2.\n * @param _depositManager DepositManager Polygon system contract to deposit tokens over the Plasma bridge (Matic).\n * @param _erc20Predicate ERC20Predicate Polygon system contract to approve when depositing to the PoS bridge.\n * @param _l1Matic matic address on l1.\n * @param _l1Weth WETH address on L1.\n */\n constructor(\n IRootChainManager _rootChainManager,\n IFxStateSender _fxStateSender,\n DepositManager _depositManager,\n address _erc20Predicate,\n address _l1Matic,\n WETH9 _l1Weth\n ) {\n rootChainManager = _rootChainManager;\n fxStateSender = _fxStateSender;\n depositManager = _depositManager;\n erc20Predicate = _erc20Predicate;\n l1Matic = _l1Matic;\n l1Weth = _l1Weth;\n }\n\n /**\n * @notice Send cross-chain message to target on Polygon.\n * @param target Contract on Polygon that will receive message.\n * @param message Data to send to target.\n */\n\n function relayMessage(address target, bytes calldata message) external payable override {\n fxStateSender.sendMessageToChild(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Polygon.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n // If the l1Token is weth then unwrap it to ETH then send the ETH to the standard bridge.\n if (l1Token == address(l1Weth)) {\n l1Weth.withdraw(amount);\n rootChainManager.depositEtherFor{ value: amount }(to);\n } else if (l1Token == l1Matic) {\n IERC20(l1Token).safeIncreaseAllowance(address(depositManager), amount);\n depositManager.depositERC20ForUser(l1Token, to, amount);\n } else {\n IERC20(l1Token).safeIncreaseAllowance(erc20Predicate, amount);\n rootChainManager.depositFor(to, l1Token, abi.encode(amount));\n }\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n}\n" }, "contracts/chain-adapters/Mock_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice Contract used for testing communication between HubPool and Adapter.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Adapter is AdapterInterface {\n event RelayMessageCalled(address target, bytes message, address caller);\n\n event RelayTokensCalled(address l1Token, address l2Token, uint256 amount, address to, address caller);\n\n Mock_Bridge public immutable bridge;\n\n constructor() {\n bridge = new Mock_Bridge();\n }\n\n function relayMessage(address target, bytes calldata message) external payable override {\n bridge.bridgeMessage(target, message);\n emit RelayMessageCalled(target, message, msg.sender);\n }\n\n function relayTokens(\n address l1Token,\n address l2Token,\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).approve(address(bridge), amount);\n bridge.bridgeTokens(l1Token, amount);\n emit RelayTokensCalled(l1Token, l2Token, amount, to, msg.sender);\n }\n}\n\n// This contract is intended to \"act like\" a simple version of an L2 bridge.\n// It's primarily meant to better reflect how a true L2 bridge interaction might work to give better gas estimates.\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Mock_Bridge {\n event BridgedTokens(address token, uint256 amount);\n event BridgedMessage(address target, bytes message);\n\n mapping(address => uint256) public deposits;\n\n function bridgeTokens(address token, uint256 amount) public {\n IERC20(token).transferFrom(msg.sender, address(this), amount);\n deposits[token] += amount;\n emit BridgedTokens(token, amount);\n }\n\n function bridgeMessage(address target, bytes calldata message) public {\n emit BridgedMessage(target, message);\n }\n}\n" }, "contracts/chain-adapters/Ethereum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to rescue funds from a Hub in the event of a misconfiguration or\n * security issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n address public immutable rescueAddress;\n\n /**\n * @notice Constructs new Adapter.\n * @param _rescueAddress Rescue address to send funds to.\n */\n constructor(address _rescueAddress) {\n rescueAddress = _rescueAddress;\n }\n\n /**\n * @notice Rescues the tokens from the calling contract.\n * @param message The encoded address of the ERC20 to send to the rescue addres.\n */\n function relayMessage(address, bytes memory message) external payable override {\n IERC20 tokenAddress = IERC20(abi.decode(message, (address)));\n\n // Transfer full balance of tokens to the rescue address.\n tokenAddress.safeTransfer(rescueAddress, tokenAddress.balanceOf(address(this)));\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n}\n" }, "contracts/chain-adapters/Ethereum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Contract containing logic to send messages from L1 to Ethereum SpokePool.\n * @notice This contract should always be deployed on the same chain as the HubPool, as it acts as a pass-through\n * contract between HubPool and SpokePool on the same chain. Its named \"Ethereum_Adapter\" because a core assumption\n * is that the HubPool will be deployed on Ethereum, so this adapter will be used to communicate between HubPool\n * and the Ethereum_SpokePool.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Ethereum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Send message to target on Ethereum.\n * @notice This function, and contract overall, is not useful in practice except that the HubPool\n * expects to interact with the SpokePool via an Adapter, so when communicating to the Ethereum_SpokePool, it must\n * send messages via this pass-through contract.\n * @param target Contract that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes calldata message) external payable override {\n _executeCall(target, message);\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Send tokens to target.\n * @param l1Token L1 token to send.\n * @param l2Token Unused parameter in this contract.\n * @param amount Amount of L1 tokens to send.\n * @param to recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for ethereum since we are assuming that the HubPool is only deployed\n // on this network.\n uint256 amount,\n address to\n ) external payable override {\n IERC20(l1Token).safeTransfer(to, amount);\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n // Note: this snippet of code is copied from Governor.sol. Source: https://github.com/UMAprotocol/protocol/blob/5b37ea818a28479c01e458389a83c3e736306b17/packages/core/contracts/oracle/implementation/Governor.sol#L190-L207\n function _executeCall(address to, bytes memory data) private {\n // Note: this snippet of code is copied from Governor.sol and modified to not include any \"value\" field.\n\n bool success;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let inputData := add(data, 0x20)\n let inputDataSize := mload(data)\n // Hardcode value to be 0 for relayed governance calls in order to avoid addressing complexity of bridging\n // value cross-chain.\n success := call(gas(), to, 0, inputData, inputDataSize, 0, 0)\n }\n require(success, \"execute call failed\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_SendTokensAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice This adapter is built for emergencies to send funds from the Hub to a Spoke in the event that a spoke pool\n * received a duplicate root bundle relay, due to some replay issue.\n */\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_SendTokensAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n uint256 public immutable l2GasPrice = 5e9;\n uint32 public immutable l2GasLimit = 2_000_000;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n }\n\n /**\n * @notice Send tokens to SpokePool. Enables HubPool admin to call relaySpokePoolAdminFunction that will trigger\n * this function.\n * @dev This performs similar logic to relayTokens in the normal Arbitrum_Adapter by sending tokens\n * the Arbitrum_SpokePool out of the HubPool.\n * @param message The encoded address of the ERC20 to send to the rescue address.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n (address l1Token, uint256 amount) = abi.decode(message, (address, uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n target,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n // Purposefully not emitting any events so as not to confuse off-chain monitors that track this event.\n // emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"relayTokens disabled\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_Adapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface ArbitrumL1InboxLike {\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256);\n}\n\ninterface ArbitrumL1ERC20GatewayLike {\n function outboundTransfer(\n address _token,\n address _to,\n uint256 _amount,\n uint256 _maxGas,\n uint256 _gasPriceBid,\n bytes calldata _data\n ) external payable returns (bytes memory);\n\n function getGateway(address _token) external view returns (address);\n}\n\n/**\n * @notice Contract containing logic to send messages from L1 to Arbitrum.\n * @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be\n * called via delegatecall, which will execute this contract's logic within the context of the originating contract.\n * For example, the HubPool will delegatecall these functions, therefore its only necessary that the HubPool's methods\n * that call this contract's logic guard against reentrancy.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_Adapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 5e9; // 5 gWei\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 2_000_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n ArbitrumL1ERC20GatewayLike public immutable l1ERC20GatewayRouter;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n * @param _l1ERC20GatewayRouter ERC20 gateway router contract to send tokens to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox, ArbitrumL1ERC20GatewayLike _l1ERC20GatewayRouter) {\n l1Inbox = _l1ArbitrumInbox;\n l1ERC20GatewayRouter = _l1ERC20GatewayRouter;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to target on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param target Contract on Arbitrum that will receive message.\n * @param message Data to send to target.\n */\n function relayMessage(address target, bytes memory message) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n target, // destAddr destination L2 contract address\n 0, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n message // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(target, message);\n }\n\n /**\n * @notice Bridge tokens to Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param l1Token L1 token to deposit.\n * @param l2Token L2 token to receive.\n * @param amount Amount of L1 tokens to deposit and L2 tokens to receive.\n * @param to Bridge recipient.\n */\n function relayTokens(\n address l1Token,\n address l2Token, // l2Token is unused for Arbitrum.\n uint256 amount,\n address to\n ) external payable override {\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // Approve the gateway, not the router, to spend the hub pool's balance. The gateway, which is different\n // per L1 token, will temporarily escrow the tokens to be bridged and pull them from this contract.\n address erc20Gateway = l1ERC20GatewayRouter.getGateway(l1Token);\n IERC20(l1Token).safeIncreaseAllowance(erc20Gateway, amount);\n\n // `outboundTransfer` expects that the caller includes a bytes message as the last param that includes the\n // maxSubmissionCost to use when creating an L2 retryable ticket: https://github.com/OffchainLabs/arbitrum/blob/e98d14873dd77513b569771f47b5e05b72402c5e/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol#L232\n bytes memory data = abi.encode(l2MaxSubmissionCost, \"\");\n\n // Note: outboundTransfer() will ultimately create a retryable ticket and set this contract's address as the\n // refund address. This means that the excess ETH to pay for the L2 transaction will be sent to the aliased\n // contract address on L2 and lost.\n l1ERC20GatewayRouter.outboundTransfer{ value: requiredL1CallValue }(\n l1Token,\n to,\n amount,\n l2GasLimit,\n l2GasPrice,\n data\n );\n\n emit TokensRelayed(l1Token, l2Token, amount, to);\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/chain-adapters/Arbitrum_RescueAdapter.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../interfaces/AdapterInterface.sol\";\nimport \"./Arbitrum_Adapter.sol\"; // Used to import `ArbitrumL1ERC20GatewayLike` and `ArbitrumL1InboxLike`\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @notice Meant to copy the Arbitrum_Adapter exactly in how it sends L1 --> L2 messages but is designed only to be\n * used by the owner of the HubPool to retrieve ETH held by its aliased address on L2. This ETH builds up because\n * `relayTokens` calls `l1ERC20GatewayRouter.outboundTransfer` which does not allow the caller to specify an L2 refund\n * address the same way that `l1Inbox.createRetryableTicket` does. This means that the alias address of the caller, the\n * HubPool in this case, receives ETH on L2. This Adapter can be used to send messages to Arbitrum specifically to send\n * transactions as if called by the aliased HubPool address.\n */\n\n// solhint-disable-next-line contract-name-camelcase\ncontract Arbitrum_RescueAdapter is AdapterInterface {\n using SafeERC20 for IERC20;\n\n // Amount of ETH allocated to pay for the base submission fee. The base submission fee is a parameter unique to\n // retryable transactions; the user is charged the base submission fee to cover the storage costs of keeping their\n // ticket’s calldata in the retry buffer. (current base submission fee is queryable via\n // ArbRetryableTx.getSubmissionPrice). ArbRetryableTicket precompile interface exists at L2 address\n // 0x000000000000000000000000000000000000006E.\n uint256 public immutable l2MaxSubmissionCost = 0.01e18;\n\n // L2 Gas price bid for immediate L2 execution attempt (queryable via standard eth*gasPrice RPC)\n uint256 public immutable l2GasPrice = 150e9;\n\n // Gas limit for immediate L2 execution attempt (can be estimated via NodeInterface.estimateRetryableTicket).\n // NodeInterface precompile interface exists at L2 address 0x00000000000000000000000000000000000000C8\n uint32 public immutable l2GasLimit = 160_000;\n\n // This address on L2 receives extra ETH that is left over after relaying a message via the inbox.\n address public immutable l2RefundL2Address;\n\n // L1 HubPool address aliased on L2: https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#address-aliasing\n address public immutable aliasedL2HubPoolAddress = 0xd297fA914353c44B2e33EBE05F21846f1048CFeB;\n\n ArbitrumL1InboxLike public immutable l1Inbox;\n\n /**\n * @notice Constructs new Adapter.\n * @param _l1ArbitrumInbox Inbox helper contract to send messages to Arbitrum.\n */\n constructor(ArbitrumL1InboxLike _l1ArbitrumInbox) {\n l1Inbox = _l1ArbitrumInbox;\n\n l2RefundL2Address = msg.sender;\n }\n\n /**\n * @notice Send cross-chain message to aliased hub pool address on Arbitrum.\n * @notice This contract must hold at least getL1CallValue() amount of ETH to send a message via the Inbox\n * successfully, or the message will get stuck.\n * @param message Data to send to aliased hub pool.\n */\n function relayMessage(address, bytes memory message) external payable override {\n uint256 valueToReturn = abi.decode(message, (uint256));\n\n uint256 requiredL1CallValue = _contractHasSufficientEthBalance();\n\n // In the rescue ETH setup, we send the transaction to the refund address, we provide a call value equal to the\n // amount we want to rescue, and we specify an empty calldata, since it's a simple ETH transfer.\n l1Inbox.createRetryableTicket{ value: requiredL1CallValue }(\n l2RefundL2Address, // destAddr destination L2 contract address\n valueToReturn, // l2CallValue call value for retryable L2 message\n l2MaxSubmissionCost, // maxSubmissionCost Max gas deducted from user's L2 balance to cover base fee\n l2RefundL2Address, // excessFeeRefundAddress maxgas * gasprice - execution cost gets credited here on L2\n l2RefundL2Address, // callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n l2GasLimit, // maxGas Max gas deducted from user's L2 balance to cover L2 execution\n l2GasPrice, // gasPriceBid price bid for L2 execution\n \"\" // data ABI encoded data of L2 message\n );\n\n emit MessageRelayed(aliasedL2HubPoolAddress, \"\");\n }\n\n /**\n * @notice Should never be called.\n */\n function relayTokens(\n address,\n address,\n uint256,\n address\n ) external payable override {\n revert(\"useless function\");\n }\n\n /**\n * @notice Returns required amount of ETH to send a message via the Inbox.\n * @return amount of ETH that this contract needs to hold in order for relayMessage to succeed.\n */\n function getL1CallValue() public pure returns (uint256) {\n return l2MaxSubmissionCost + l2GasPrice * l2GasLimit;\n }\n\n function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {\n requiredL1CallValue = getL1CallValue();\n require(address(this).balance >= requiredL1CallValue, \"Insufficient ETH balance\");\n }\n}\n" }, "contracts/test/MerkleLibTest.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"../MerkleLib.sol\";\nimport \"../HubPoolInterface.sol\";\nimport \"../SpokePoolInterface.sol\";\n\n/**\n * @notice Contract to test the MerkleLib.\n */\ncontract MerkleLibTest {\n mapping(uint256 => uint256) public claimedBitMap;\n\n uint256 public claimedBitMap1D;\n\n function verifyPoolRebalance(\n bytes32 root,\n HubPoolInterface.PoolRebalanceLeaf memory rebalance,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyPoolRebalance(root, rebalance, proof);\n }\n\n function verifyRelayerRefund(\n bytes32 root,\n SpokePoolInterface.RelayerRefundLeaf memory refund,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifyRelayerRefund(root, refund, proof);\n }\n\n function verifySlowRelayFulfillment(\n bytes32 root,\n SpokePoolInterface.RelayData memory slowRelayFulfillment,\n bytes32[] memory proof\n ) public pure returns (bool) {\n return MerkleLib.verifySlowRelayFulfillment(root, slowRelayFulfillment, proof);\n }\n\n function isClaimed(uint256 index) public view returns (bool) {\n return MerkleLib.isClaimed(claimedBitMap, index);\n }\n\n function setClaimed(uint256 index) public {\n MerkleLib.setClaimed(claimedBitMap, index);\n }\n\n function isClaimed1D(uint8 index) public view returns (bool) {\n return MerkleLib.isClaimed1D(claimedBitMap1D, index);\n }\n\n function setClaimed1D(uint8 index) public {\n claimedBitMap1D = MerkleLib.setClaimed1D(claimedBitMap1D, index);\n }\n}\n" }, "contracts/Boba_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./Ovm_SpokePool.sol\";\n\n/**\n * @notice Boba Spoke pool. Note that the l2ETH and l2WETH are the opposite as that in Optimism.\n */\ncontract Boba_SpokePool is Ovm_SpokePool {\n /**\n * @notice Construct the OVM Boba SpokePool.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _crossDomainAdmin,\n address _hubPool,\n address timerAddress\n )\n Ovm_SpokePool(\n _crossDomainAdmin,\n _hubPool,\n 0x4200000000000000000000000000000000000006,\n 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000,\n timerAddress\n )\n {}\n}\n" }, "contracts/Arbitrum_SpokePool.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./SpokePool.sol\";\n\ninterface StandardBridgeLike {\n function outboundTransfer(\n address _l1Token,\n address _to,\n uint256 _amount,\n bytes calldata _data\n ) external payable returns (bytes memory);\n}\n\n/**\n * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.\n */\ncontract Arbitrum_SpokePool is SpokePool {\n // Address of the Arbitrum L2 token gateway to send funds to L1.\n address public l2GatewayRouter;\n\n // Admin controlled mapping of arbitrum tokens to L1 counterpart. L1 counterpart addresses\n // are necessary params used when bridging tokens to L1.\n mapping(address => address) public whitelistedTokens;\n\n event ArbitrumTokensBridged(address indexed l1Token, address target, uint256 numberOfTokensBridged);\n event SetL2GatewayRouter(address indexed newL2GatewayRouter);\n event WhitelistedTokens(address indexed l2Token, address indexed l1Token);\n\n /**\n * @notice Construct the AVM SpokePool.\n * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin.\n * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin.\n * @param _hubPool Hub pool address to set. Can be changed by admin.\n * @param _wethAddress Weth address for this network to set.\n * @param timerAddress Timer address to set.\n */\n constructor(\n address _l2GatewayRouter,\n address _crossDomainAdmin,\n address _hubPool,\n address _wethAddress,\n address timerAddress\n ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {\n _setL2GatewayRouter(_l2GatewayRouter);\n }\n\n modifier onlyFromCrossDomainAdmin() {\n require(msg.sender == _applyL1ToL2Alias(crossDomainAdmin), \"ONLY_COUNTERPART_GATEWAY\");\n _;\n }\n\n /********************************************************\n * ARBITRUM-SPECIFIC CROSS-CHAIN ADMIN FUNCTIONS *\n ********************************************************/\n\n /**\n * @notice Change L2 gateway router. Callable only by admin.\n * @param newL2GatewayRouter New L2 gateway router.\n */\n function setL2GatewayRouter(address newL2GatewayRouter) public onlyAdmin nonReentrant {\n _setL2GatewayRouter(newL2GatewayRouter);\n }\n\n /**\n * @notice Add L2 -> L1 token mapping. Callable only by admin.\n * @param l2Token Arbitrum token.\n * @param l1Token Ethereum version of l2Token.\n */\n function whitelistToken(address l2Token, address l1Token) public onlyAdmin nonReentrant {\n _whitelistToken(l2Token, l1Token);\n }\n\n /**************************************\n * INTERNAL FUNCTIONS *\n **************************************/\n\n function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {\n // Check that the Ethereum counterpart of the L2 token is stored on this contract.\n address ethereumTokenToBridge = whitelistedTokens[relayerRefundLeaf.l2TokenAddress];\n require(ethereumTokenToBridge != address(0), \"Uninitialized mainnet token\");\n StandardBridgeLike(l2GatewayRouter).outboundTransfer(\n ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over.\n hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract.\n relayerRefundLeaf.amountToReturn, // _amount.\n \"\" // _data. We don't need to send any data for the bridging action.\n );\n emit ArbitrumTokensBridged(address(0), hubPool, relayerRefundLeaf.amountToReturn);\n }\n\n function _setL2GatewayRouter(address _l2GatewayRouter) internal {\n l2GatewayRouter = _l2GatewayRouter;\n emit SetL2GatewayRouter(l2GatewayRouter);\n }\n\n function _whitelistToken(address _l2Token, address _l1Token) internal {\n whitelistedTokens[_l2Token] = _l1Token;\n emit WhitelistedTokens(_l2Token, _l1Token);\n }\n\n // L1 addresses are transformed during l1->l2 calls.\n // See https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing for more information.\n // This cannot be pulled directly from Arbitrum contracts because their contracts are not 0.8.X compatible and\n // this operation takes advantage of overflows, whose behavior changed in 0.8.0.\n function _applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {\n // Allows overflows as explained above.\n unchecked {\n l2Address = address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));\n }\n }\n\n // Apply AVM-specific transformation to cross domain admin address on L1.\n function _requireAdminSender() internal override onlyFromCrossDomainAdmin {}\n}\n" }, "contracts/test/PolygonMocks.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract RootChainManagerMock {\n function depositEtherFor(address user) external payable {} // solhint-disable-line no-empty-blocks\n\n function depositFor(\n address user,\n address rootToken,\n bytes calldata depositData\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract FxStateSenderMock {\n // solhint-disable-next-line no-empty-blocks\n function sendMessageToChild(address _receiver, bytes calldata _data) external {}\n}\n\ncontract DepositManagerMock {\n function depositERC20ForUser(\n address token,\n address user,\n uint256 amount // solhint-disable-next-line no-empty-blocks\n ) external {} // solhint-disable-line no-empty-blocks\n}\n\ncontract PolygonRegistryMock {\n // solhint-disable-next-line no-empty-blocks\n function erc20Predicate() external returns (address predicate) {}\n}\n\ncontract PolygonERC20PredicateMock {\n // solhint-disable-next-line no-empty-blocks\n function startExitWithBurntTokens(bytes calldata data) external {}\n}\n\ncontract PolygonERC20Mock is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"Test ERC20\", \"TEST\") {}\n\n // solhint-disable-next-line no-empty-blocks\n function withdraw(uint256 amount) external {}\n}\n" }, "@uma/core/contracts/oracle/interfaces/OptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract OptimisticOracleInterface {\n // Struct representing the state of a price request.\n enum State {\n Invalid, // Never requested.\n Requested, // Requested, no other actions taken.\n Proposed, // Proposed, but not expired or disputed yet.\n Expired, // Proposed, not disputed, past liveness.\n Disputed, // Disputed, but no DVM price returned yet.\n Resolved, // Disputed and DVM price is available.\n Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n }\n\n // Struct representing a price request.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n * This can be changed with a subsequent call to setBond().\n */\n function requestPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Set the proposal bond associated with a price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param bond custom bond amount to set.\n * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n * changed again with a subsequent call to setBond().\n */\n function setBond(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 bond\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n * bond, so there is still profit to be made even if the reward is refunded.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n */\n function setRefundOnDispute(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual;\n\n /**\n * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n * being auto-resolved.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param customLiveness new custom liveness.\n */\n function setCustomLiveness(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n uint256 customLiveness\n ) external virtual;\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param proposer address to set as the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address proposer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value for an existing price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was value (the proposal was incorrect).\n */\n function disputePriceFor(\n address disputer,\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price value for an existing price request with an active proposal.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n * hasn't been settled.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return resolved price.\n */\n function settleAndGetPrice(\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (int256);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) external virtual returns (uint256 payout);\n\n /**\n * @notice Gets the current data structure containing all information about a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the Request data structure.\n */\n function getRequest(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (Request memory);\n\n /**\n * @notice Returns the state of a price request.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return the State enum value.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (State);\n\n /**\n * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @return true if price has resolved or settled, false otherwise.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint256 timestamp,\n bytes memory ancillaryData\n ) public view virtual returns (bool);\n\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n view\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/SkinnyOptimisticOracleInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../interfaces/OptimisticOracleInterface.sol\";\n\n/**\n * @title Interface for the gas-cost-reduced version of the OptimisticOracle.\n * @notice Differences from normal OptimisticOracle:\n * - refundOnDispute: flag is removed, by default there are no refunds on disputes.\n * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset\n * after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be\n * set in `requestPrice`, which has an expanded input set.\n * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price\n * can be fetched via the `Settle` event or the return value of `settle`.\n * - general changes to interface: Functions that interact with existing requests all require the parameters of the\n * request to modify to be passed as input. These parameters must match with the existing request parameters or the\n * function will revert. This change reflects the internal refactor to store hashed request parameters instead of the\n * full request struct.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n */\nabstract contract SkinnyOptimisticOracleInterface {\n // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct\n // in that refundOnDispute is removed.\n struct Request {\n address proposer; // Address of the proposer.\n address disputer; // Address of the disputer.\n IERC20 currency; // ERC20 token used to pay rewards and fees.\n bool settled; // True if the request is settled.\n int256 proposedPrice; // Price that the proposer submitted.\n int256 resolvedPrice; // Price resolved once the request is settled.\n uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n uint256 customLiveness; // Custom liveness value set by the requester.\n }\n\n // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n // to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n\n /**\n * @notice Requests a new price.\n * @param identifier price identifier being requested.\n * @param timestamp timestamp of the price being requested.\n * @param ancillaryData ancillary data representing additional args being passed with the price request.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.\n */\n function requestPrice(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n * from this proposal. However, any bonds are pulled from the caller.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePriceFor(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address proposer,\n int256 proposedPrice\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Proposes a price value where caller is the proposer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * propose a price for.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function proposePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to\n * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer\n * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.\n * @dev The caller is the requester, but the proposer can be customized.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n * which could make sense if the contract requests and proposes the value in the same call or\n * provides its own reward system.\n * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.\n * @param customLiveness custom proposal liveness to set for request.\n * @param proposer address to set as the proposer.\n * @param proposedPrice price being proposed.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the proposer once settled if the proposal is correct.\n */\n function requestAndProposePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n IERC20 currency,\n uint256 reward,\n uint256 bond,\n uint256 customLiveness,\n address proposer,\n int256 proposedPrice\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @param disputer address to set as the disputer.\n * @param requester sender of the initial price request.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePriceFor(\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request,\n address disputer,\n address requester\n ) public virtual returns (uint256 totalBond);\n\n /**\n * @notice Disputes a price request with an active proposal where caller is the disputer.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * dispute.\n * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n * the disputer once settled if the dispute was valid (the proposal was incorrect).\n */\n function disputePrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 totalBond);\n\n /**\n * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters whose hash must match the request that the caller wants to\n * settle.\n * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n * the returned bonds as well as additional rewards.\n * @return resolvedPrice the price that the request settled to.\n */\n function settle(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (uint256 payout, int256 resolvedPrice);\n\n /**\n * @notice Computes the current state of a price request. See the State enum for more details.\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters.\n * @return the State.\n */\n function getState(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) external virtual returns (OptimisticOracleInterface.State);\n\n /**\n * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).\n * @param requester sender of the initial price request.\n * @param identifier price identifier to identify the existing request.\n * @param timestamp timestamp to identify the existing request.\n * @param ancillaryData ancillary data of the price being requested.\n * @param request price request parameters. The hash of these parameters must match with the request hash that is\n * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method\n * will revert.\n * @return boolean indicating true if price exists and false if not.\n */\n function hasPrice(\n address requester,\n bytes32 identifier,\n uint32 timestamp,\n bytes memory ancillaryData,\n Request memory request\n ) public virtual returns (bool);\n\n /**\n * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.\n * @param ancillaryData ancillary data of the price being requested.\n * @param requester sender of the initial price request.\n * @return the stamped ancillary bytes.\n */\n function stampAncillaryData(bytes memory ancillaryData, address requester)\n public\n pure\n virtual\n returns (bytes memory);\n}\n" }, "@uma/core/contracts/oracle/interfaces/StoreInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../common/implementation/FixedPoint.sol\";\n\n/**\n * @title Interface that allows financial contracts to pay oracle fees for their use of the system.\n */\ninterface StoreInterface {\n /**\n * @notice Pays Oracle fees in ETH to the store.\n * @dev To be used by contracts whose margin currency is ETH.\n */\n function payOracleFees() external payable;\n\n /**\n * @notice Pays oracle fees in the margin currency, erc20Address, to the store.\n * @dev To be used if the margin currency is an ERC20 token rather than ETH.\n * @param erc20Address address of the ERC20 token used to pay the fee.\n * @param amount number of tokens to transfer. An approval for at least this amount must exist.\n */\n function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;\n\n /**\n * @notice Computes the regular oracle fees that a contract should pay for a period.\n * @param startTime defines the beginning time from which the fee is paid.\n * @param endTime end time until which the fee is paid.\n * @param pfc \"profit from corruption\", or the maximum amount of margin currency that a\n * token sponsor could extract from the contract through corrupting the price feed in their favor.\n * @return regularFee amount owed for the duration from start to end time for the given pfc.\n * @return latePenalty for paying the fee after the deadline.\n */\n function computeRegularFee(\n uint256 startTime,\n uint256 endTime,\n FixedPoint.Unsigned calldata pfc\n ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);\n\n /**\n * @notice Computes the final oracle fees that a contract should pay at settlement.\n * @param currency token used to pay the final fee.\n * @return finalFee amount due.\n */\n function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);\n}\n" }, "@uma/core/contracts/common/implementation/FixedPoint.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/SignedSafeMath.sol\";\n\n/**\n * @title Library for fixed point arithmetic on uints\n */\nlibrary FixedPoint {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For unsigned values:\n // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.\n uint256 private constant FP_SCALING_FACTOR = 10**18;\n\n // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------\n struct Unsigned {\n uint256 rawValue;\n }\n\n /**\n * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a uint to convert into a FixedPoint.\n * @return the converted FixedPoint.\n */\n function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {\n return Unsigned(a.mul(FP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if equal, or False.\n */\n function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a < b`, or False.\n */\n function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledUint(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {\n return fromUnscaledUint(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the minimum of `a` and `b`.\n */\n function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the maximum of `a` and `b`.\n */\n function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the sum of `a` and `b`.\n */\n function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return add(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts two `Unsigned`s, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the difference of `a` and `b`.\n */\n function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return sub(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.\n * @param a a uint256.\n * @param b a FixedPoint.\n * @return the difference of `a` and `b`.\n */\n function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return sub(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Multiplies two `Unsigned`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as a uint256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because FP_SCALING_FACTOR != 0.\n return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.\n * @param b a uint256.\n * @return the product of `a` and `b`.\n */\n function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Unsigned`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 mulRaw = a.rawValue.mul(b.rawValue);\n uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;\n uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);\n if (mod != 0) {\n return Unsigned(mulFloor.add(1));\n } else {\n return Unsigned(mulFloor);\n }\n }\n\n /**\n * @notice Multiplies an `Unsigned` and an unscaled uint256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.\n * @param b a FixedPoint.\n * @return the product of `a` and `b`.\n */\n function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Since b is an uint, there is no risk of truncation and we can just mul it normally\n return Unsigned(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as a uint256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n return Unsigned(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a uint256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {\n return div(fromUnscaledUint(a), b);\n }\n\n /**\n * @notice Divides one `Unsigned` by an `Unsigned` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {\n uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);\n uint256 divFloor = aScaled.div(b.rawValue);\n uint256 mod = aScaled.mod(b.rawValue);\n if (mod != 0) {\n return Unsigned(divFloor.add(1));\n } else {\n return Unsigned(divFloor);\n }\n }\n\n /**\n * @notice Divides one `Unsigned` by an unscaled uint256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Unsigned(a.rawValue.div(b))\"\n // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.\n // This creates the possibility of overflow if b is very large.\n return divCeil(a, fromUnscaledUint(b));\n }\n\n /**\n * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint numerator.\n * @param b a uint256 denominator.\n * @return output is `a` to the power of `b`.\n */\n function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {\n output = fromUnscaledUint(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n\n // ------------------------------------------------- SIGNED -------------------------------------------------------------\n // Supports 18 decimals. E.g., 1e18 represents \"1\", 5e17 represents \"0.5\".\n // For signed values:\n // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.\n int256 private constant SFP_SCALING_FACTOR = 10**18;\n\n struct Signed {\n int256 rawValue;\n }\n\n function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {\n require(a.rawValue >= 0, \"Negative value provided\");\n return Unsigned(uint256(a.rawValue));\n }\n\n function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {\n require(a.rawValue <= uint256(type(int256).max), \"Unsigned too large\");\n return Signed(int256(a.rawValue));\n }\n\n /**\n * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.\n * @param a int to convert into a FixedPoint.Signed.\n * @return the converted FixedPoint.Signed.\n */\n function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {\n return Signed(a.mul(SFP_SCALING_FACTOR));\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a int256.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue == fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if equal, or False.\n */\n function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue == b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue > fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a > b`, or False.\n */\n function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue > b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue >= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is greater than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a >= b`, or False.\n */\n function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue >= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a < b`, or False.\n */\n function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue < fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a < b`, or False.\n */\n function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue < b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {\n return a.rawValue <= b.rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {\n return a.rawValue <= fromUnscaledInt(b).rawValue;\n }\n\n /**\n * @notice Whether `a` is less than or equal to `b`.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return True if `a <= b`, or False.\n */\n function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {\n return fromUnscaledInt(a).rawValue <= b.rawValue;\n }\n\n /**\n * @notice The minimum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the minimum of `a` and `b`.\n */\n function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue < b.rawValue ? a : b;\n }\n\n /**\n * @notice The maximum of `a` and `b`.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the maximum of `a` and `b`.\n */\n function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return a.rawValue > b.rawValue ? a : b;\n }\n\n /**\n * @notice Adds two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.add(b.rawValue));\n }\n\n /**\n * @notice Adds an `Signed` to an unscaled int, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the sum of `a` and `b`.\n */\n function add(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return add(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts two `Signed`s, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.sub(b.rawValue));\n }\n\n /**\n * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the difference of `a` and `b`.\n */\n function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return sub(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.\n * @param a an int256.\n * @param b a FixedPoint.Signed.\n * @return the difference of `a` and `b`.\n */\n function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return sub(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Multiplies two `Signed`s, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is\n // stored internally as an int256 ~10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which\n // would round to 3, but this computation produces the result 2.\n // No need to use SafeMath because SFP_SCALING_FACTOR != 0.\n return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.\n * @dev This will \"floor\" the product.\n * @param a a FixedPoint.Signed.\n * @param b an int256.\n * @return the product of `a` and `b`.\n */\n function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Multiplies two `Signed`s and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 mulRaw = a.rawValue.mul(b.rawValue);\n int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = mulRaw % SFP_SCALING_FACTOR;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(mulTowardsZero.add(valueToAdd));\n } else {\n return Signed(mulTowardsZero);\n }\n }\n\n /**\n * @notice Multiplies an `Signed` and an unscaled int256 and \"ceil's\" the product, reverting on overflow.\n * @param a a FixedPoint.Signed.\n * @param b a FixedPoint.Signed.\n * @return the product of `a` and `b`.\n */\n function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Since b is an int, there is no risk of truncation and we can just mul it normally\n return Signed(a.rawValue.mul(b));\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n // There are two caveats with this computation:\n // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.\n // 10^41 is stored internally as an int256 10^59.\n // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which\n // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.\n return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(Signed memory a, int256 b) internal pure returns (Signed memory) {\n return Signed(a.rawValue.div(b));\n }\n\n /**\n * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.\n * @dev This will \"floor\" the quotient.\n * @param a an int256 numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function div(int256 a, Signed memory b) internal pure returns (Signed memory) {\n return div(fromUnscaledInt(a), b);\n }\n\n /**\n * @notice Divides one `Signed` by an `Signed` and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b a FixedPoint denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {\n int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);\n int256 divTowardsZero = aScaled.div(b.rawValue);\n // Manual mod because SignedSafeMath doesn't support it.\n int256 mod = aScaled % b.rawValue;\n if (mod != 0) {\n bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);\n int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);\n return Signed(divTowardsZero.add(valueToAdd));\n } else {\n return Signed(divTowardsZero);\n }\n }\n\n /**\n * @notice Divides one `Signed` by an unscaled int256 and \"ceil's\" the quotient, reverting on overflow or division by 0.\n * @param a a FixedPoint numerator.\n * @param b an int256 denominator.\n * @return the quotient of `a` divided by `b`.\n */\n function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {\n // Because it is possible that a quotient gets truncated, we can't just call \"Signed(a.rawValue.div(b))\"\n // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.\n // This creates the possibility of overflow if b is very large.\n return divAwayFromZero(a, fromUnscaledInt(b));\n }\n\n /**\n * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.\n * @dev This will \"floor\" the result.\n * @param a a FixedPoint.Signed.\n * @param b a uint256 (negative exponents are not allowed).\n * @return output is `a` to the power of `b`.\n */\n function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {\n output = fromUnscaledInt(1);\n for (uint256 i = 0; i < b; i = i.add(1)) {\n output = mul(output, a);\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeMath.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" @@ -185,22 +185,22 @@ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SignedSafeMath {\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n return a / b;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n return a - b;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n return a + b;\n }\n}\n" }, "contracts/LpTokenFactory.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\nimport \"./interfaces/LpTokenFactoryInterface.sol\";\n\nimport \"@uma/core/contracts/common/implementation/ExpandedERC20.sol\";\n\n/**\n * @notice Factory to create new LP ERC20 tokens that represent a liquidity provider's position. HubPool is the\n * intended client of this contract.\n */\ncontract LpTokenFactory is LpTokenFactoryInterface {\n /**\n * @notice Deploys new LP token for L1 token. Sets caller as minter and burner of token.\n * @param l1Token L1 token to name in LP token name.\n * @return address of new LP token.\n */\n function createLpToken(address l1Token) public returns (address) {\n ExpandedERC20 lpToken = new ExpandedERC20(\n _concatenate(\"Across V2 \", IERC20Metadata(l1Token).name(), \" LP Token\"), // LP Token Name\n _concatenate(\"Av2-\", IERC20Metadata(l1Token).symbol(), \"-LP\"), // LP Token Symbol\n IERC20Metadata(l1Token).decimals() // LP Token Decimals\n );\n\n lpToken.addMinter(msg.sender); // Set the caller as the LP Token's minter.\n lpToken.addBurner(msg.sender); // Set the caller as the LP Token's burner.\n lpToken.resetOwner(msg.sender); // Set the caller as the LP Token's owner.\n\n return address(lpToken);\n }\n\n function _concatenate(\n string memory a,\n string memory b,\n string memory c\n ) internal pure returns (string memory) {\n return string(abi.encodePacked(a, b, c));\n }\n}\n" }, "contracts/interfaces/LpTokenFactoryInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface LpTokenFactoryInterface {\n function createLpToken(address l1Token) external returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/FinderInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n /**\n * @notice Updates the address of the contract that implements `interfaceName`.\n * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n * @param implementationAddress address of the deployed contract that implements the interface.\n */\n function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n /**\n * @notice Gets the address of the contract that implements the given `interfaceName`.\n * @param interfaceName queried interface.\n * @return implementationAddress address of the deployed contract that implements the interface.\n */\n function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n" }, "@uma/core/contracts/oracle/interfaces/IdentifierWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.\n */\ninterface IdentifierWhitelistInterface {\n /**\n * @notice Adds the provided identifier as a supported identifier.\n * @dev Price requests using this identifier will succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function addSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Removes the identifier from the whitelist.\n * @dev Price requests using this identifier will no longer succeed after this call.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n */\n function removeSupportedIdentifier(bytes32 identifier) external;\n\n /**\n * @notice Checks whether an identifier is on the whitelist.\n * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.\n * @return bool if the identifier is supported (or not).\n */\n function isIdentifierSupported(bytes32 identifier) external view returns (bool);\n}\n" }, "@uma/core/contracts/common/interfaces/AddressWhitelistInterface.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface AddressWhitelistInterface {\n function addToWhitelist(address newElement) external;\n\n function removeFromWhitelist(address newElement) external;\n\n function isOnWhitelist(address newElement) external view returns (bool);\n\n function getWhitelist() external view returns (address[] memory);\n}\n" }, "@uma/core/contracts/oracle/implementation/Constants.sol": { - "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Stores common interface names used throughout the DVM by registration in the Finder.\n */\nlibrary OracleInterfaces {\n bytes32 public constant Oracle = \"Oracle\";\n bytes32 public constant IdentifierWhitelist = \"IdentifierWhitelist\";\n bytes32 public constant Store = \"Store\";\n bytes32 public constant FinancialContractsAdmin = \"FinancialContractsAdmin\";\n bytes32 public constant Registry = \"Registry\";\n bytes32 public constant CollateralWhitelist = \"CollateralWhitelist\";\n bytes32 public constant OptimisticOracle = \"OptimisticOracle\";\n bytes32 public constant Bridge = \"Bridge\";\n bytes32 public constant GenericHandler = \"GenericHandler\";\n bytes32 public constant SkinnyOptimisticOracle = \"SkinnyOptimisticOracle\";\n bytes32 public constant ChildMessenger = \"ChildMessenger\";\n bytes32 public constant OracleHub = \"OracleHub\";\n bytes32 public constant OracleSpoke = \"OracleSpoke\";\n}\n\n/**\n * @title Commonly re-used values for contracts associated with the OptimisticOracle.\n */\nlibrary OptimisticOracleConstraints {\n // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.\n // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible\n // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which\n // refuses to accept a price request made with ancillary data length over a certain size.\n uint256 public constant ancillaryBytesLimit = 8192;\n}\n" } }, "settings": {